Initial ia64 checkin.
3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile
3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk
+41a26ebcqaSGVQ8qTMwpPwOJSJ7qSw xen/arch/ia64/privop.c
+41a26ebc4BOHDUsT0TSnryPeV2xfRA xen/arch/ia64/process.c
+41a26ebcJ30TFl1v2kR8rqpEBvOtVw xen/arch/ia64/regionreg.c
+41a26ebc--sjlYZQxmIxyCx3jw70qA xen/arch/ia64/vcpu.c
+41a26ebc4jSBGQOuyNIPDST58mNbBw xen/arch/ia64/xenasm.S
3ddb79bcZbRBzT3elFWSX7u6NtMagQ xen/arch/x86/Makefile
3ddb79bcBQF85CfLS4i1WGZ4oLLaCA xen/arch/x86/Rules.mk
3e5636e5FAYZ5_vQnmgwFJfSdmO5Mw xen/arch/x86/acpi.c
--- /dev/null
+/*
+ * Privileged operation "API" handling functions.
+ *
+ * Copyright (C) 2004 Hewlett-Packard Co.
+ * Dan Magenheimer (dan.magenheimer@hp.com)
+ *
+ */
+
+#include <asm/privop.h>
+#include <asm/privify.h>
+#include <asm/vcpu.h>
+#include <asm/processor.h>
+#include <asm/delay.h> // Debug only
+//#include <debug.h>
+
+long priv_verbose=0;
+
+/**************************************************************************
+Hypercall bundle creation
+**************************************************************************/
+
+
+void build_hypercall_bundle(UINT64 *imva, UINT64 breakimm, UINT64 hypnum, UINT64 ret)
+{
+ INST64_A5 slot0;
+ INST64_I19 slot1;
+ INST64_B4 slot2;
+ IA64_BUNDLE bundle;
+
+ // slot1: mov r2 = hypnum (low 20 bits)
+ slot0.inst = 0;
+ slot0.qp = 0; slot0.r1 = 2; slot0.r3 = 0; slot0.major = 0x9;
+ slot0.imm7b = hypnum; slot0.imm9d = hypnum >> 7;
+ slot0.imm5c = hypnum >> 16; slot0.s = 0;
+ // slot1: break breakimm
+ slot1.inst = 0;
+ slot1.qp = 0; slot1.x6 = 0; slot1.x3 = 0; slot1.major = 0x0;
+ slot1.imm20 = breakimm; slot1.i = breakimm >> 20;
+ // if ret slot2: br.ret.sptk.many rp
+ // else slot2: br.cond.sptk.many rp
+ slot2.inst = 0; slot2.qp = 0; slot2.p = 1; slot2.b2 = 0;
+ slot2.wh = 0; slot2.d = 0; slot2.major = 0x0;
+ if (ret) {
+ slot2.btype = 4; slot2.x6 = 0x21;
+ }
+ else {
+ slot2.btype = 0; slot2.x6 = 0x20;
+ }
+
+ bundle.i64[0] = 0; bundle.i64[1] = 0;
+ bundle.template = 0x11;
+ bundle.slot0 = slot0.inst; bundle.slot2 = slot2.inst;
+ bundle.slot1a = slot1.inst; bundle.slot1b = slot1.inst >> 18;
+
+ *imva++ = bundle.i64[0]; *imva = bundle.i64[1];
+}
+
+/**************************************************************************
+Privileged operation emulation routines
+**************************************************************************/
+
+IA64FAULT priv_rfi(VCPU *vcpu, INST64 inst)
+{
+ return vcpu_rfi(vcpu);
+}
+
+IA64FAULT priv_bsw0(VCPU *vcpu, INST64 inst)
+{
+ return vcpu_bsw0(vcpu);
+}
+
+IA64FAULT priv_bsw1(VCPU *vcpu, INST64 inst)
+{
+ return vcpu_bsw1(vcpu);
+}
+
+IA64FAULT priv_cover(VCPU *vcpu, INST64 inst)
+{
+ return vcpu_cover(vcpu);
+}
+
+IA64FAULT priv_ptc_l(VCPU *vcpu, INST64 inst)
+{
+ UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
+ UINT64 addr_range;
+
+ addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
+ return vcpu_ptc_l(vcpu,vadr,addr_range);
+}
+
+IA64FAULT priv_ptc_e(VCPU *vcpu, INST64 inst)
+{
+ UINT src = inst.M28.r3;
+
+ // NOTE: ptc_e with source gr > 63 is emulated as a fc r(y-64)
+ if (src > 63) return(vcpu_fc(vcpu,vcpu_get_gr(vcpu,src - 64)));
+ return vcpu_ptc_e(vcpu,vcpu_get_gr(vcpu,src));
+}
+
+IA64FAULT priv_ptc_g(VCPU *vcpu, INST64 inst)
+{
+ UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
+ UINT64 addr_range;
+
+ addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
+ return vcpu_ptc_g(vcpu,vadr,addr_range);
+}
+
+IA64FAULT priv_ptc_ga(VCPU *vcpu, INST64 inst)
+{
+ UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
+ UINT64 addr_range;
+
+ addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
+ return vcpu_ptc_ga(vcpu,vadr,addr_range);
+}
+
+IA64FAULT priv_ptr_d(VCPU *vcpu, INST64 inst)
+{
+ UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
+ UINT64 addr_range;
+
+ addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
+ return vcpu_ptr_d(vcpu,vadr,addr_range);
+}
+
+IA64FAULT priv_ptr_i(VCPU *vcpu, INST64 inst)
+{
+ UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
+ UINT64 addr_range;
+
+ addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
+ return vcpu_ptr_i(vcpu,vadr,addr_range);
+}
+
+IA64FAULT priv_tpa(VCPU *vcpu, INST64 inst)
+{
+ UINT64 padr;
+ UINT fault;
+ UINT src = inst.M46.r3;
+
+ // NOTE: tpa with source gr > 63 is emulated as a ttag rx=r(y-64)
+ if (src > 63)
+ fault = vcpu_ttag(vcpu,vcpu_get_gr(vcpu,src-64),&padr);
+ else fault = vcpu_tpa(vcpu,vcpu_get_gr(vcpu,src),&padr);
+ if (fault == IA64_NO_FAULT)
+ return vcpu_set_gr(vcpu, inst.M46.r1, padr);
+ else return fault;
+}
+
+IA64FAULT priv_tak(VCPU *vcpu, INST64 inst)
+{
+ UINT64 key;
+ UINT fault;
+ UINT src = inst.M46.r3;
+
+ // NOTE: tak with source gr > 63 is emulated as a thash rx=r(y-64)
+ if (src > 63)
+ fault = vcpu_thash(vcpu,vcpu_get_gr(vcpu,src-64),&key);
+ else fault = vcpu_tak(vcpu,vcpu_get_gr(vcpu,src),&key);
+ if (fault == IA64_NO_FAULT)
+ return vcpu_set_gr(vcpu, inst.M46.r1, key);
+ else return fault;
+}
+
+/************************************
+ * Insert translation register/cache
+************************************/
+
+IA64FAULT priv_itr_d(VCPU *vcpu, INST64 inst)
+{
+ UINT64 fault, itir, ifa, pte, slot;
+
+ //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
+ if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
+ return(IA64_ILLOP_FAULT);
+ if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
+ return(IA64_ILLOP_FAULT);
+ pte = vcpu_get_gr(vcpu,inst.M42.r2);
+ slot = vcpu_get_gr(vcpu,inst.M42.r3);
+
+ return (vcpu_itr_d(vcpu,slot,pte,itir,ifa));
+}
+
+IA64FAULT priv_itr_i(VCPU *vcpu, INST64 inst)
+{
+ UINT64 fault, itir, ifa, pte, slot;
+
+ //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
+ if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
+ return(IA64_ILLOP_FAULT);
+ if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
+ return(IA64_ILLOP_FAULT);
+ pte = vcpu_get_gr(vcpu,inst.M42.r2);
+ slot = vcpu_get_gr(vcpu,inst.M42.r3);
+
+ return (vcpu_itr_i(vcpu,slot,pte,itir,ifa));
+}
+
+IA64FAULT priv_itc_d(VCPU *vcpu, INST64 inst)
+{
+ UINT64 fault, itir, ifa, pte;
+
+ //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
+ if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
+ return(IA64_ILLOP_FAULT);
+ if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
+ return(IA64_ILLOP_FAULT);
+ pte = vcpu_get_gr(vcpu,inst.M41.r2);
+
+ return (vcpu_itc_d(vcpu,pte,itir,ifa));
+}
+
+IA64FAULT priv_itc_i(VCPU *vcpu, INST64 inst)
+{
+ UINT64 fault, itir, ifa, pte;
+
+ //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
+ if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
+ return(IA64_ILLOP_FAULT);
+ if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
+ return(IA64_ILLOP_FAULT);
+ pte = vcpu_get_gr(vcpu,inst.M41.r2);
+
+ return (vcpu_itc_i(vcpu,pte,itir,ifa));
+}
+
+/*************************************
+ * Moves to semi-privileged registers
+*************************************/
+
+IA64FAULT priv_mov_to_ar_imm(VCPU *vcpu, INST64 inst)
+{
+ // I27 and M30 are identical for these fields
+ UINT64 ar3 = inst.M30.ar3;
+ UINT64 imm = vcpu_get_gr(vcpu,inst.M30.imm);
+ return (vcpu_set_ar(vcpu,ar3,imm));
+}
+
+IA64FAULT priv_mov_to_ar_reg(VCPU *vcpu, INST64 inst)
+{
+ // I26 and M29 are identical for these fields
+ UINT64 ar3 = inst.M29.ar3;
+
+ if (inst.M29.r2 > 63 && inst.M29.ar3 < 8) { // privified mov from kr
+ UINT64 val;
+ if (vcpu_get_ar(vcpu,ar3,&val) != IA64_ILLOP_FAULT)
+ return vcpu_set_gr(vcpu, inst.M29.r2-64, val);
+ else return IA64_ILLOP_FAULT;
+ }
+ else {
+ UINT64 r2 = vcpu_get_gr(vcpu,inst.M29.r2);
+ return (vcpu_set_ar(vcpu,ar3,r2));
+ }
+}
+
+/********************************
+ * Moves to privileged registers
+********************************/
+
+IA64FAULT priv_mov_to_pkr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+ UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+ return (vcpu_set_pkr(vcpu,r3,r2));
+}
+
+IA64FAULT priv_mov_to_rr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+ UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+ return (vcpu_set_rr(vcpu,r3,r2));
+}
+
+IA64FAULT priv_mov_to_dbr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+ UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+ return (vcpu_set_dbr(vcpu,r3,r2));
+}
+
+IA64FAULT priv_mov_to_ibr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+ UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+ return (vcpu_set_ibr(vcpu,r3,r2));
+}
+
+IA64FAULT priv_mov_to_pmc(VCPU *vcpu, INST64 inst)
+{
+ UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+ UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+ return (vcpu_set_pmc(vcpu,r3,r2));
+}
+
+IA64FAULT priv_mov_to_pmd(VCPU *vcpu, INST64 inst)
+{
+ UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+ UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+ return (vcpu_set_pmd(vcpu,r3,r2));
+}
+
+unsigned long to_cr_cnt[128] = { 0 };
+
+IA64FAULT priv_mov_to_cr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 val = vcpu_get_gr(vcpu, inst.M32.r2);
+ to_cr_cnt[inst.M32.cr3]++;
+ switch (inst.M32.cr3) {
+ case 0: return vcpu_set_dcr(vcpu,val);
+ case 1: return vcpu_set_itm(vcpu,val);
+ case 2: return vcpu_set_iva(vcpu,val);
+ case 8: return vcpu_set_pta(vcpu,val);
+ case 16:return vcpu_set_ipsr(vcpu,val);
+ case 17:return vcpu_set_isr(vcpu,val);
+ case 19:return vcpu_set_iip(vcpu,val);
+ case 20:return vcpu_set_ifa(vcpu,val);
+ case 21:return vcpu_set_itir(vcpu,val);
+ case 22:return vcpu_set_iipa(vcpu,val);
+ case 23:return vcpu_set_ifs(vcpu,val);
+ case 24:return vcpu_set_iim(vcpu,val);
+ case 25:return vcpu_set_iha(vcpu,val);
+ case 64:return vcpu_set_lid(vcpu,val);
+ case 65:return IA64_ILLOP_FAULT;
+ case 66:return vcpu_set_tpr(vcpu,val);
+ case 67:return vcpu_set_eoi(vcpu,val);
+ case 68:return IA64_ILLOP_FAULT;
+ case 69:return IA64_ILLOP_FAULT;
+ case 70:return IA64_ILLOP_FAULT;
+ case 71:return IA64_ILLOP_FAULT;
+ case 72:return vcpu_set_itv(vcpu,val);
+ case 73:return vcpu_set_pmv(vcpu,val);
+ case 74:return vcpu_set_cmcv(vcpu,val);
+ case 80:return vcpu_set_lrr0(vcpu,val);
+ case 81:return vcpu_set_lrr1(vcpu,val);
+ default: return IA64_ILLOP_FAULT;
+ }
+}
+
+IA64FAULT priv_rsm(VCPU *vcpu, INST64 inst)
+{
+ UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm;
+ return vcpu_reset_psr_sm(vcpu,imm24);
+}
+
+IA64FAULT priv_ssm(VCPU *vcpu, INST64 inst)
+{
+ UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm;
+ return vcpu_set_psr_sm(vcpu,imm24);
+}
+
+/**
+ * @todo Check for reserved bits and return IA64_RSVDREG_FAULT.
+ */
+IA64FAULT priv_mov_to_psr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 val = vcpu_get_gr(vcpu, inst.M35.r2);
+ return vcpu_set_psr_l(vcpu,val);
+}
+
+/**********************************
+ * Moves from privileged registers
+ **********************************/
+
+IA64FAULT priv_mov_from_rr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 val;
+ IA64FAULT fault;
+
+ if (inst.M43.r1 > 63) { // privified mov from cpuid
+ fault = vcpu_get_cpuid(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+ if (fault == IA64_NO_FAULT)
+ return vcpu_set_gr(vcpu, inst.M43.r1-64, val);
+ }
+ else {
+ fault = vcpu_get_rr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+ if (fault == IA64_NO_FAULT)
+ return vcpu_set_gr(vcpu, inst.M43.r1, val);
+ }
+ return fault;
+}
+
+IA64FAULT priv_mov_from_pkr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 val;
+ IA64FAULT fault;
+
+ fault = vcpu_get_pkr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+ if (fault == IA64_NO_FAULT)
+ return vcpu_set_gr(vcpu, inst.M43.r1, val);
+ else return fault;
+}
+
+IA64FAULT priv_mov_from_dbr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 val;
+ IA64FAULT fault;
+
+ fault = vcpu_get_dbr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+ if (fault == IA64_NO_FAULT)
+ return vcpu_set_gr(vcpu, inst.M43.r1, val);
+ else return fault;
+}
+
+IA64FAULT priv_mov_from_ibr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 val;
+ IA64FAULT fault;
+
+ fault = vcpu_get_ibr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+ if (fault == IA64_NO_FAULT)
+ return vcpu_set_gr(vcpu, inst.M43.r1, val);
+ else return fault;
+}
+
+IA64FAULT priv_mov_from_pmc(VCPU *vcpu, INST64 inst)
+{
+ UINT64 val;
+ IA64FAULT fault;
+
+ fault = vcpu_get_pmc(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+ if (fault == IA64_NO_FAULT)
+ return vcpu_set_gr(vcpu, inst.M43.r1, val);
+ else return fault;
+}
+
+unsigned long from_cr_cnt[128] = { 0 };
+
+#define cr_get(cr) \
+ ((fault = vcpu_get_##cr(vcpu,&val)) == IA64_NO_FAULT) ? \
+ vcpu_set_gr(vcpu, tgt, val) : fault;
+
+IA64FAULT priv_mov_from_cr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 tgt = inst.M33.r1;
+ UINT64 val;
+ IA64FAULT fault;
+
+ from_cr_cnt[inst.M33.cr3]++;
+ switch (inst.M33.cr3) {
+ case 0: return cr_get(dcr);
+ case 1: return cr_get(itm);
+ case 2: return cr_get(iva);
+ case 8: return cr_get(pta);
+ case 16:return cr_get(ipsr);
+ case 17:return cr_get(isr);
+ case 19:return cr_get(iip);
+ case 20:return cr_get(ifa);
+ case 21:return cr_get(itir);
+ case 22:return cr_get(iipa);
+ case 23:return cr_get(ifs);
+ case 24:return cr_get(iim);
+ case 25:return cr_get(iha);
+ case 64:return cr_get(lid);
+ case 65:return cr_get(ivr);
+ case 66:return cr_get(tpr);
+ case 67:return vcpu_set_gr(vcpu,tgt,0L);
+ case 68:return cr_get(irr0);
+ case 69:return cr_get(irr1);
+ case 70:return cr_get(irr2);
+ case 71:return cr_get(irr3);
+ case 72:return cr_get(itv);
+ case 73:return cr_get(pmv);
+ case 74:return cr_get(cmcv);
+ case 80:return cr_get(lrr0);
+ case 81:return cr_get(lrr1);
+ default: return IA64_ILLOP_FAULT;
+ }
+ return IA64_ILLOP_FAULT;
+}
+
+IA64FAULT priv_mov_from_psr(VCPU *vcpu, INST64 inst)
+{
+ UINT64 tgt = inst.M33.r1;
+ UINT64 val;
+ IA64FAULT fault;
+
+ if ((fault = vcpu_get_psr(vcpu,&val)) == IA64_NO_FAULT)
+ return vcpu_set_gr(vcpu, tgt, val);
+ else return fault;
+}
+
+/**************************************************************************
+Privileged operation decode and dispatch routines
+**************************************************************************/
+
+IA64_SLOT_TYPE slot_types[0x20][3] = {
+ {M, I, I}, {M, I, I}, {M, I, I}, {M, I, I},
+ {M, I, ILLEGAL}, {M, I, ILLEGAL},
+ {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL},
+ {M, M, I}, {M, M, I}, {M, M, I}, {M, M, I},
+ {M, F, I}, {M, F, I},
+ {M, M, F}, {M, M, F},
+ {M, I, B}, {M, I, B},
+ {M, B, B}, {M, B, B},
+ {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL},
+ {B, B, B}, {B, B, B},
+ {M, M, B}, {M, M, B},
+ {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL},
+ {M, F, B}, {M, F, B},
+ {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL}
+};
+
+// pointer to privileged emulation function
+typedef IA64FAULT (*PPEFCN)(VCPU *vcpu, INST64 inst);
+
+PPEFCN Mpriv_funcs[64] = {
+ priv_mov_to_rr, priv_mov_to_dbr, priv_mov_to_ibr, priv_mov_to_pkr,
+ priv_mov_to_pmc, priv_mov_to_pmd, 0, 0,
+ 0, priv_ptc_l, priv_ptc_g, priv_ptc_ga,
+ priv_ptr_d, priv_ptr_i, priv_itr_d, priv_itr_i,
+ priv_mov_from_rr, priv_mov_from_dbr, priv_mov_from_ibr, priv_mov_from_pkr,
+ priv_mov_from_pmc, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, priv_tpa, priv_tak,
+ 0, 0, 0, 0,
+ priv_mov_from_cr, priv_mov_from_psr, 0, 0,
+ 0, 0, 0, 0,
+ priv_mov_to_cr, priv_mov_to_psr, priv_itc_d, priv_itc_i,
+ 0, 0, 0, 0,
+ priv_ptc_e, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+struct {
+ unsigned long mov_to_ar_imm;
+ unsigned long mov_to_ar_reg;
+ unsigned long ssm;
+ unsigned long rsm;
+ unsigned long rfi;
+ unsigned long bsw0;
+ unsigned long bsw1;
+ unsigned long cover;
+ unsigned long Mpriv_cnt[64];
+} privcnt = { 0 };
+
+unsigned long privop_trace = 0;
+
+IA64FAULT
+priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl)
+{
+ IA64_BUNDLE bundle, __get_domain_bundle(UINT64);
+ int slot;
+ IA64_SLOT_TYPE slot_type;
+ INST64 inst;
+ PPEFCN pfunc;
+ unsigned long ipsr = regs->cr_ipsr;
+ UINT64 iip = regs->cr_iip;
+ int x6;
+
+ // make a local copy of the bundle containing the privop
+#if 1
+ bundle = __get_domain_bundle(iip);
+ if (!bundle.i64[0] && !bundle.i64[1]) return IA64_RETRY;
+#else
+#ifdef AVOIDING_POSSIBLE_DOMAIN_TLB_MISS
+ //TODO: this needs to check for faults and behave accordingly
+ if (!vcpu_get_iip_bundle(&bundle)) return IA64_DTLB_FAULT;
+#else
+if (iip < 0x10000) {
+ printf("priv_handle_op: unlikely iip=%p,b0=%p\n",iip,regs->b0);
+ dummy();
+}
+ bundle = *(IA64_BUNDLE *)iip;
+#endif
+#endif
+#if 0
+ if (iip==0xa000000100001820) {
+ static int firstpagefault = 1;
+ if (firstpagefault) {
+ printf("*** First time to domain page fault!\n"); firstpagefault=0;
+ }
+ }
+#endif
+ if (privop_trace) {
+ static long i = 400;
+ //if (i > 0) printf("privop @%p\n",iip);
+ if (i > 0) printf("priv_handle_op: @%p, itc=%lx, itm=%lx\n",
+ iip,ia64_get_itc(),ia64_get_itm());
+ i--;
+ }
+ slot = ((struct ia64_psr *)&ipsr)->ri;
+ if (!slot) inst.inst = (bundle.i64[0]>>5) & MASK_41;
+ else if (slot == 1)
+ inst.inst = ((bundle.i64[0]>>46) | bundle.i64[1]<<18) & MASK_41;
+ else if (slot == 2) inst.inst = (bundle.i64[1]>>23) & MASK_41;
+ else printf("priv_handle_op: illegal slot: %d\n", slot);
+
+ slot_type = slot_types[bundle.template][slot];
+ if (priv_verbose) {
+ printf("priv_handle_op: checking bundle at 0x%lx (op=0x%016lx) slot %d (type=%d)\n",
+ iip, (UINT64)inst.inst, slot, slot_type);
+ }
+ if (slot_type == B && inst.generic.major == 0 && inst.B8.x6 == 0x0) {
+ // break instr for privified cover
+ }
+ else if (privlvl != 2) return (IA64_ILLOP_FAULT);
+ switch (slot_type) {
+ case M:
+ if (inst.generic.major == 0) {
+#if 0
+ if (inst.M29.x6 == 0 && inst.M29.x3 == 0) {
+ privcnt.cover++;
+ return priv_cover(vcpu,inst);
+ }
+#endif
+ if (inst.M29.x3 != 0) break;
+ if (inst.M30.x4 == 8 && inst.M30.x2 == 2) {
+ privcnt.mov_to_ar_imm++;
+ return priv_mov_to_ar_imm(vcpu,inst);
+ }
+ if (inst.M44.x4 == 6) {
+ privcnt.ssm++;
+ return priv_ssm(vcpu,inst);
+ }
+ if (inst.M44.x4 == 7) {
+ privcnt.rsm++;
+ return priv_rsm(vcpu,inst);
+ }
+ break;
+ }
+ else if (inst.generic.major != 1) break;
+ x6 = inst.M29.x6;
+ if (x6 == 0x2a) {
+ privcnt.mov_to_ar_reg++;
+ return priv_mov_to_ar_reg(vcpu,inst);
+ }
+ if (inst.M29.x3 != 0) break;
+ if (!(pfunc = Mpriv_funcs[x6])) break;
+ if (x6 == 0x1e || x6 == 0x1f) { // tpa or tak are "special"
+ if (inst.M46.r3 > 63) {
+ if (x6 == 0x1e) x6 = 0x1b;
+ else x6 = 0x1a;
+ }
+ }
+ privcnt.Mpriv_cnt[x6]++;
+ return (*pfunc)(vcpu,inst);
+ break;
+ case B:
+ if (inst.generic.major != 0) break;
+ if (inst.B8.x6 == 0x08) {
+ IA64FAULT fault;
+ privcnt.rfi++;
+ fault = priv_rfi(vcpu,inst);
+ if (fault == IA64_NO_FAULT) fault = IA64_RFI_IN_PROGRESS;
+ return fault;
+ }
+ if (inst.B8.x6 == 0x0c) {
+ privcnt.bsw0++;
+ return priv_bsw0(vcpu,inst);
+ }
+ if (inst.B8.x6 == 0x0d) {
+ privcnt.bsw1++;
+ return priv_bsw1(vcpu,inst);
+ }
+ if (inst.B8.x6 == 0x0) { // break instr for privified cover
+ privcnt.cover++;
+ return priv_cover(vcpu,inst);
+ }
+ break;
+ case I:
+ if (inst.generic.major != 0) break;
+#if 0
+ if (inst.I26.x6 == 0 && inst.I26.x3 == 0) {
+ privcnt.cover++;
+ return priv_cover(vcpu,inst);
+ }
+#endif
+ if (inst.I26.x3 != 0) break; // I26.x3 == I27.x3
+ if (inst.I26.x6 == 0x2a) {
+ privcnt.mov_to_ar_reg++;
+ return priv_mov_to_ar_reg(vcpu,inst);
+ }
+ if (inst.I27.x6 == 0x0a) {
+ privcnt.mov_to_ar_imm++;
+ return priv_mov_to_ar_imm(vcpu,inst);
+ }
+ break;
+ default:
+ break;
+ }
+ //printf("We who are about do die salute you\n");
+ printf("handle_op: can't handle privop at 0x%lx (op=0x%016lx) slot %d (type=%d)\n",
+ iip, (UINT64)inst.inst, slot, slot_type);
+ //printf("vtop(0x%lx)==0x%lx\r\n", iip, tr_vtop(iip));
+ //thread_mozambique("privop fault\n");
+ return (IA64_ILLOP_FAULT);
+}
+
+/** Emulate a privileged operation.
+ *
+ * This should probably return 0 on success and the "trap number"
+ * (e.g. illegal operation for bad register, priv op for an
+ * instruction that isn't allowed, etc.) on "failure"
+ *
+ * @param vcpu virtual cpu
+ * @param isrcode interrupt service routine code
+ * @return fault
+ */
+IA64FAULT
+priv_emulate(VCPU *vcpu, REGS *regs, UINT64 isr)
+{
+ IA64FAULT fault;
+ UINT64 ipsr = regs->cr_ipsr;
+ UINT64 isrcode = (isr >> 4) & 0xf;
+ int privlvl;
+
+ // handle privops masked as illops? and breaks (6)
+ if (isrcode != 1 && isrcode != 2 && isrcode != 0 && isrcode != 6) {
+ printf("priv_emulate: isrcode != 0 or 1 or 2\n");
+ printf("priv_emulate: returning ILLOP, not implemented!\n");
+ while (1);
+ return IA64_ILLOP_FAULT;
+ }
+ //if (isrcode != 1 && isrcode != 2) return 0;
+ vcpu_set_regs(vcpu,regs);
+ privlvl = (ipsr & IA64_PSR_CPL) >> IA64_PSR_CPL0_BIT;
+ // its OK for a privified-cover to be executed in user-land
+ fault = priv_handle_op(vcpu,regs,privlvl);
+ if (fault == IA64_NO_FAULT) { // success!!
+ // update iip/ipsr to point to the next instruction
+ (void)vcpu_increment_iip(vcpu);
+ }
+ else if (fault == IA64_EXTINT_VECTOR) {
+ // update iip/ipsr before delivering interrupt
+ (void)vcpu_increment_iip(vcpu);
+ }
+ else if (fault == IA64_RFI_IN_PROGRESS) return fault;
+ // success but don't update to next instruction
+ else if (fault == IA64_RETRY) {
+ //printf("Priv emulate gets IA64_RETRY\n");
+ //printf("priv_emulate: returning RETRY, not implemented!\n");
+ //while (1);
+ // don't update iip/ipsr, deliver
+
+ vcpu_force_data_miss(vcpu,regs->cr_iip);
+ return IA64_RETRY;
+ }
+ else if (priv_verbose) printf("unhandled operation from handle_op\n");
+// if (fault == IA64_ILLOP_FAULT) {
+// printf("priv_emulate: returning ILLOP, not implemented!\n");
+// while (1);
+// }
+ return fault;
+}
+
+
+/**************************************************************************
+Privileged operation instrumentation routines
+**************************************************************************/
+
+char *Mpriv_str[64] = {
+ "mov_to_rr", "mov_to_dbr", "mov_to_ibr", "mov_to_pkr",
+ "mov_to_pmc", "mov_to_pmd", "<0x06>", "<0x07>",
+ "<0x08>", "ptc_l", "ptc_g", "ptc_ga",
+ "ptr_d", "ptr_i", "itr_d", "itr_i",
+ "mov_from_rr", "mov_from_dbr", "mov_from_ibr", "mov_from_pkr",
+ "mov_from_pmc", "<0x15>", "<0x16>", "<0x17>",
+ "<0x18>", "<0x19>", "privified-thash", "privified-ttag",
+ "<0x1c>", "<0x1d>", "tpa", "tak",
+ "<0x20>", "<0x21>", "<0x22>", "<0x23>",
+ "mov_from_cr", "mov_from_psr", "<0x26>", "<0x27>",
+ "<0x28>", "<0x29>", "<0x2a>", "<0x2b>",
+ "mov_to_cr", "mov_to_psr", "itc_d", "itc_i",
+ "<0x30>", "<0x31>", "<0x32>", "<0x33>",
+ "ptc_e", "<0x35>", "<0x36>", "<0x37>",
+ "<0x38>", "<0x39>", "<0x3a>", "<0x3b>",
+ "<0x3c>", "<0x3d>", "<0x3e>", "<0x3f>"
+};
+
+#define RS "Rsvd"
+char *cr_str[128] = {
+ "dcr","itm","iva",RS,RS,RS,RS,RS,
+ "pta",RS,RS,RS,RS,RS,RS,RS,
+ "ipsr","isr",RS,"iip","ifa","itir","iipa","ifs",
+ "iim","iha",RS,RS,RS,RS,RS,RS,
+ RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS,
+ RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS,
+ "lid","ivr","tpr","eoi","irr0","irr1","irr2","irr3",
+ "itv","pmv","cmcv",RS,RS,RS,RS,RS,
+ "lrr0","lrr1",RS,RS,RS,RS,RS,RS,
+ RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS,
+ RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS,
+ RS,RS,RS,RS,RS,RS,RS,RS
+};
+
+void dump_privop_counts(void)
+{
+ int i, j;
+ UINT64 sum = 0;
+
+ // this is ugly and should probably produce sorted output
+ // but it will have to do for now
+ sum += privcnt.mov_to_ar_imm; sum += privcnt.mov_to_ar_reg;
+ sum += privcnt.ssm; sum += privcnt.rsm;
+ sum += privcnt.rfi; sum += privcnt.bsw0;
+ sum += privcnt.bsw1; sum += privcnt.cover;
+ for (i=0; i < 64; i++) sum += privcnt.Mpriv_cnt[i];
+ printf("Privop statistics: (Total privops: %ld)\r\n",sum);
+ if (privcnt.mov_to_ar_imm)
+ printf("%10d %s [%d%%]\r\n", privcnt.mov_to_ar_imm,
+ "mov_to_ar_imm", (privcnt.mov_to_ar_imm*100L)/sum);
+ if (privcnt.mov_to_ar_reg)
+ printf("%10d %s [%d%%]\r\n", privcnt.mov_to_ar_reg,
+ "mov_to_ar_reg", (privcnt.mov_to_ar_reg*100L)/sum);
+ if (privcnt.ssm)
+ printf("%10d %s [%d%%]\r\n", privcnt.ssm,
+ "ssm", (privcnt.ssm*100L)/sum);
+ if (privcnt.rsm)
+ printf("%10d %s [%d%%]\r\n", privcnt.rsm,
+ "rsm", (privcnt.rsm*100L)/sum);
+ if (privcnt.rfi)
+ printf("%10d %s [%d%%]\r\n", privcnt.rfi,
+ "rfi", (privcnt.rfi*100L)/sum);
+ if (privcnt.bsw0)
+ printf("%10d %s [%d%%]\r\n", privcnt.bsw0,
+ "bsw0", (privcnt.bsw0*100L)/sum);
+ if (privcnt.bsw1)
+ printf("%10d %s [%d%%]\r\n", privcnt.bsw1,
+ "bsw1", (privcnt.bsw1*100L)/sum);
+ if (privcnt.cover)
+ printf("%10d %s [%d%%]\r\n", privcnt.cover,
+ "cover", (privcnt.cover*100L)/sum);
+ for (i=0; i < 64; i++) if (privcnt.Mpriv_cnt[i]) {
+ if (!Mpriv_str[i]) printf("PRIVSTRING NULL!!\r\n");
+ else printf("%10d %s [%d%%]\r\n", privcnt.Mpriv_cnt[i],
+ Mpriv_str[i], (privcnt.Mpriv_cnt[i]*100L)/sum);
+ if (i == 0x24) { // mov from CR
+ printf(" [");
+ for (j=0; j < 128; j++) if (from_cr_cnt[j]) {
+ if (!cr_str[j])
+ printf("PRIVSTRING NULL!!\r\n");
+ printf("%s(%d),",cr_str[j],from_cr_cnt[j]);
+ }
+ printf("]\r\n");
+ }
+ else if (i == 0x2c) { // mov to CR
+ printf(" [");
+ for (j=0; j < 128; j++) if (to_cr_cnt[j]) {
+ if (!cr_str[j])
+ printf("PRIVSTRING NULL!!\r\n");
+ printf("%s(%d),",cr_str[j],to_cr_cnt[j]);
+ }
+ printf("]\r\n");
+ }
+ }
+}
+
+void zero_privop_counts(void)
+{
+ int i, j;
+
+ // this is ugly and should probably produce sorted output
+ // but it will have to do for now
+ printf("Zeroing privop statistics\r\n");
+ privcnt.mov_to_ar_imm = 0; privcnt.mov_to_ar_reg = 0;
+ privcnt.ssm = 0; privcnt.rsm = 0;
+ privcnt.rfi = 0; privcnt.bsw0 = 0;
+ privcnt.bsw1 = 0; privcnt.cover = 0;
+ for (i=0; i < 64; i++) privcnt.Mpriv_cnt[i] = 0;
+ for (j=0; j < 128; j++) from_cr_cnt[j] = 0;
+ for (j=0; j < 128; j++) to_cr_cnt[j] = 0;
+}
--- /dev/null
+/*
+ * Miscellaneous process/domain related routines
+ *
+ * Copyright (C) 2004 Hewlett-Packard Co.
+ * Dan Magenheimer (dan.magenheimer@hp.com)
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/lib.h>
+#include <xen/errno.h>
+#include <xen/sched.h>
+#include <xen/smp.h>
+#include <asm/ptrace.h>
+#include <xen/delay.h>
+
+#include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */
+#include <asm/sal.h> /* FOR struct ia64_sal_retval */
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/desc.h>
+#include <asm/ldt.h>
+#include <xen/irq.h>
+#include <xen/event.h>
+#include <asm/regionreg.h>
+#include <asm/privop.h>
+#include <asm/vcpu.h>
+#include <asm/ia64_int.h>
+#include <asm/hpsim_ssc.h>
+#include <asm/dom_fw.h>
+
+extern struct ia64_sal_retval pal_emulator_static(UINT64);
+extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64);
+
+extern unsigned long dom0_start, dom0_size;
+
+#define IA64_PSR_CPL1 (__IA64_UL(1) << IA64_PSR_CPL1_BIT)
+// note IA64_PSR_PK removed from following, why is this necessary?
+#define DELIVER_PSR_SET (IA64_PSR_IC | IA64_PSR_I | \
+ IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_CPL1 | \
+ IA64_PSR_IT | IA64_PSR_BN)
+
+#define DELIVER_PSR_CLR (IA64_PSR_AC | IA64_PSR_DFL | IA64_PSR_DFH | \
+ IA64_PSR_SP | IA64_PSR_DI | IA64_PSR_SI | \
+ IA64_PSR_DB | IA64_PSR_LP | IA64_PSR_TB | \
+ IA64_PSR_CPL | IA64_PSR_MC | IA64_PSR_IS | \
+ IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \
+ IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA)
+
+#define PSCB(x) x->shared_info->arch
+
+extern unsigned long vcpu_verbose;
+
+long do_iopl(domid_t domain, unsigned int new_io_pl)
+{
+ dummy();
+ return 0;
+}
+
+void schedule_tail(struct domain *next)
+{
+ unsigned long rr7;
+ printk("current=%lx,shared_info=%lx\n",current,current->shared_info);
+ printk("next=%lx,shared_info=%lx\n",next,next->shared_info);
+ if (rr7 = load_region_regs(current)) {
+ printk("schedule_tail: change to rr7 not yet implemented\n");
+ }
+}
+
+extern TR_ENTRY *match_tr(struct domain *d, unsigned long ifa);
+
+void tdpfoo(void) { }
+
+// given a domain virtual address, pte and pagesize, extract the metaphysical
+// address, convert the pte for a physical address for (possibly different)
+// Xen PAGE_SIZE and return modified pte. (NOTE: TLB insert should use
+// PAGE_SIZE!)
+unsigned long translate_domain_pte(unsigned long pteval,
+ unsigned long address, unsigned long itir)
+{
+ struct domain *d = (struct domain *) current;
+ unsigned long mask, pteval2, mpaddr;
+ unsigned long lookup_domain_mpa(struct domain *,unsigned long);
+ extern struct domain *dom0;
+ extern unsigned long dom0_start, dom0_size;
+
+ // FIXME address had better be pre-validated on insert
+ mask = (1L << ((itir >> 2) & 0x3f)) - 1;
+ mpaddr = ((pteval & _PAGE_PPN_MASK) & ~mask) | (address & mask);
+ if (d == dom0) {
+ if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
+ //printk("translate_domain_pte: out-of-bounds dom0 mpaddr %p! itc=%lx...\n",mpaddr,ia64_get_itc());
+ tdpfoo();
+ }
+ }
+ else if ((mpaddr >> PAGE_SHIFT) > d->max_pages) {
+ printf("translate_domain_pte: bad mpa=%p (> %p),vadr=%p,pteval=%p,itir=%p\n",
+ mpaddr,d->max_pages<<PAGE_SHIFT,address,pteval,itir);
+ tdpfoo();
+ }
+ pteval2 = lookup_domain_mpa(d,mpaddr);
+ pteval2 &= _PAGE_PPN_MASK; // ignore non-addr bits
+ pteval2 |= _PAGE_PL_2; // force PL0->2 (PL3 is unaffected)
+ pteval2 = (pteval & ~_PAGE_PPN_MASK) | pteval2;
+ return pteval2;
+}
+
+// given a current domain metaphysical address, return the physical address
+unsigned long translate_domain_mpaddr(unsigned long mpaddr)
+{
+ extern unsigned long lookup_domain_mpa(struct domain *,unsigned long);
+ unsigned long pteval;
+
+ if (current == dom0) {
+ if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
+ printk("translate_domain_mpaddr: out-of-bounds dom0 mpaddr %p! continuing...\n",mpaddr);
+ tdpfoo();
+ }
+ }
+ pteval = lookup_domain_mpa(current,mpaddr);
+ return ((pteval & _PAGE_PPN_MASK) | (mpaddr & ~PAGE_MASK));
+}
+
+void reflect_interruption(unsigned long ifa, unsigned long isr, unsigned long itiriim, struct pt_regs *regs, unsigned long vector)
+{
+ unsigned long vcpu_get_ipsr_int_state(struct domain *,unsigned long);
+ unsigned long vcpu_get_rr_ve(struct domain *,unsigned long);
+ unsigned long vcpu_get_itir_on_fault(struct domain *,unsigned long);
+ struct domain *d = (struct domain *) current;
+
+ if (vector == IA64_EXTINT_VECTOR) {
+
+ extern unsigned long vcpu_verbose, privop_trace;
+ static first_extint = 1;
+ if (first_extint) {
+ printf("Delivering first extint to domain: ifa=%p, isr=%p, itir=%p, iip=%p\n",ifa,isr,itiriim,regs->cr_iip);
+ //privop_trace = 1; vcpu_verbose = 1;
+ first_extint = 0;
+ }
+ }
+ if (!PSCB(d).interrupt_collection_enabled) {
+ if (!(PSCB(d).ipsr & IA64_PSR_DT)) {
+ printf("psr.dt off, trying to deliver nested dtlb!\n");
+ while(1);
+ }
+ vector &= ~0xf;
+ if (vector != IA64_DATA_TLB_VECTOR &&
+ vector != IA64_DATA_TLB_VECTOR) {
+printf("psr.ic off, delivering fault=%lx,iip=%p,isr=%p,PSCB.iip=%p\n",
+ vector,regs->cr_iip,isr,PSCB(d).iip);
+ while(1);
+
+ }
+//printf("Delivering NESTED DATA TLB fault\n");
+ vector = IA64_DATA_NESTED_TLB_VECTOR;
+ regs->cr_iip = ((unsigned long) PSCB(d).iva + vector) & ~0xffUL;
+ regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET;
+// NOTE: nested trap must NOT pass PSCB address
+ //regs->r31 = (unsigned long) &PSCB(d);
+ return;
+
+ }
+ if ((vector & 0xf) != IA64_FORCED_IFA) PSCB(d).ifa = ifa;
+ else ifa = PSCB(d).ifa;
+ vector &= ~0xf;
+// always deliver on ALT vector (for now?) because no VHPT
+// if (!vcpu_get_rr_ve(d,ifa)) {
+ if (vector == IA64_DATA_TLB_VECTOR)
+ vector = IA64_ALT_DATA_TLB_VECTOR;
+ else if (vector == IA64_INST_TLB_VECTOR)
+ vector = IA64_ALT_INST_TLB_VECTOR;
+// }
+ PSCB(d).unat = regs->ar_unat; // not sure if this is really needed?
+ PSCB(d).precover_ifs = regs->cr_ifs;
+ vcpu_bsw0(d);
+ PSCB(d).ipsr = vcpu_get_ipsr_int_state(d,regs->cr_ipsr);
+ if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR)
+ PSCB(d).iim = itiriim;
+ else PSCB(d).itir = vcpu_get_itir_on_fault(d,ifa);
+ PSCB(d).isr = isr; // this is unnecessary except for interrupts!
+ PSCB(d).iip = regs->cr_iip;
+ PSCB(d).ifs = 0;
+ PSCB(d).incomplete_regframe = 0;
+
+ regs->cr_iip = ((unsigned long) PSCB(d).iva + vector) & ~0xffUL;
+ regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET;
+// FIXME: NEED TO PASS PSCB, BUT **NOT** IN R31 WHICH IS BEING USED FOR ar.pr
+// IN ANY CASE, PASS PINNED ADDRESS, NOT THIS ONE
+ //regs->r31 = (unsigned long) &PSCB(d);
+
+ PSCB(d).interrupt_delivery_enabled = 0;
+ PSCB(d).interrupt_collection_enabled = 0;
+}
+
+void foodpi(void) {}
+
+// ONLY gets called from ia64_leave_kernel
+// ONLY call with interrupts disabled?? (else might miss one?)
+// NEVER successful if already reflecting a trap/fault because psr.i==0
+void deliver_pending_interrupt(struct pt_regs *regs)
+{
+ struct domain *d = (struct domain *) current;
+ // FIXME: Will this work properly if doing an RFI???
+ if (!is_idle_task(d) && user_mode(regs)) {
+ vcpu_poke_timer(d);
+ if (vcpu_deliverable_interrupts(d)) {
+ unsigned long isr = regs->cr_ipsr & IA64_PSR_RI;
+ foodpi();
+ reflect_interruption(0,isr,0,regs,IA64_EXTINT_VECTOR);
+ }
+ }
+}
+
+int handle_lazy_cover(struct domain *d, unsigned long isr, struct pt_regs *regs)
+{
+ if (!PSCB(d).interrupt_collection_enabled) {
+ if (isr & IA64_ISR_IR) {
+// printf("Handling lazy cover\n");
+ PSCB(d).ifs = regs->cr_ifs;
+ PSCB(d).incomplete_regframe = 1;
+ regs->cr_ifs = 0;
+ return(1); // retry same instruction with cr.ifs off
+ }
+ }
+ return(0);
+}
+
+#define IS_XEN_ADDRESS(d,a) ((a >= d->xen_vastart) && (a <= d->xen_vaend))
+
+void xen_handle_domain_access(unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir)
+{
+ struct domain *d = (struct domain *) current;
+ TR_ENTRY *trp;
+ unsigned long psr = regs->cr_ipsr, mask, flags;
+ unsigned long iip = regs->cr_iip;
+ // FIXME should validate address here
+ unsigned long pteval, mpaddr;
+ unsigned long lookup_domain_mpa(struct domain *,unsigned long);
+ IA64FAULT fault;
+ extern void __get_domain_bundle(void);
+
+// NEED TO HANDLE THREE CASES:
+// 1) domain is in metaphysical mode
+// 2) domain address is in TR
+// 3) domain address is not in TR (reflect data miss)
+
+ // got here trying to read a privop bundle
+ //if (d->metaphysical_mode) {
+ if (d->metaphysical_mode && !(address>>61)) { //FIXME
+ if (d == dom0) {
+ if (address < dom0_start || address >= dom0_start + dom0_size) {
+ printk("xen_handle_domain_access: out-of-bounds"
+ "dom0 mpaddr %p! continuing...\n",mpaddr);
+ tdpfoo();
+ }
+ }
+ pteval = lookup_domain_mpa(d,address);
+ //FIXME: check return value?
+ // would be nice to have a counter here
+ vcpu_itc_no_srlz(d,2,address,pteval,PAGE_SHIFT);
+ return;
+ }
+if (address < 0x4000) printf("WARNING: page_fault @%p, iip=%p\n",address,iip);
+ if (*(unsigned long *)__get_domain_bundle != iip) {
+ printf("Bad user space access @%p ",address);
+ printf("iip=%p, ipsr=%p, b0=%p\n",iip,psr,regs->b0);
+ while(1);
+ }
+
+ fault = vcpu_tpa(d,address,&mpaddr);
+ if (fault != IA64_NO_FAULT) {
+ // this is hardcoded to handle __get_domain_bundle only
+ regs->r8 = 0; regs->r9 = 0;
+ regs->cr_iip += 0x20;
+ //regs->cr_iip |= (2UL << IA64_PSR_RI_BIT);
+ return;
+ }
+ if (d == dom0) {
+ if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
+ printk("xen_handle_domain_access: vcpu_tpa returned out-of-bounds dom0 mpaddr %p! continuing...\n",mpaddr);
+ tdpfoo();
+ }
+ }
+ pteval = lookup_domain_mpa(d,mpaddr);
+ // would be nice to have a counter here
+ //printf("Handling privop data TLB miss\n");
+ // FIXME, must be inlined or potential for nested fault here!
+ vcpu_itc_no_srlz(d,2,address,pteval,PAGE_SHIFT);
+}
+
+void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir)
+{
+ struct domain *d = (struct domain *) current;
+ TR_ENTRY *trp;
+ unsigned long psr = regs->cr_ipsr, mask, flags;
+ unsigned long iip = regs->cr_iip;
+ // FIXME should validate address here
+ unsigned long pteval, mpaddr;
+ unsigned long lookup_domain_mpa(struct domain *,unsigned long);
+ unsigned long is_data = !((isr >> IA64_ISR_X_BIT) & 1UL);
+ unsigned long vector;
+ IA64FAULT fault;
+
+
+ //The right way is put in VHPT and take another miss!
+
+ // weak attempt to avoid doing both I/D tlb insert to avoid
+ // problems for privop bundle fetch, doesn't work, deal with later
+ if (IS_XEN_ADDRESS(d,iip) && !IS_XEN_ADDRESS(d,address)) {
+ xen_handle_domain_access(address, isr, regs, itir);
+
+ return;
+ }
+
+ // FIXME: no need to pass itir in to this routine as we need to
+ // compute the virtual itir anyway (based on domain's RR.ps)
+ // AND ACTUALLY reflect_interruption doesn't use it anyway!
+ itir = vcpu_get_itir_on_fault(d,address);
+
+ if (d->metaphysical_mode && (is_data || !(address>>61))) { //FIXME
+ // FIXME should validate mpaddr here
+ if (d == dom0) {
+ if (address < dom0_start || address >= dom0_start + dom0_size) {
+ printk("ia64_do_page_fault: out-of-bounds dom0 mpaddr %p, iip=%p! continuing...\n",address,iip);
+ printk("ia64_do_page_fault: out-of-bounds dom0 mpaddr %p, old iip=%p!\n",address,d->shared_info->arch.iip);
+ tdpfoo();
+ }
+ }
+ pteval = lookup_domain_mpa(d,address);
+ // FIXME, must be inlined or potential for nested fault here!
+ vcpu_itc_no_srlz(d,is_data?2:1,address,pteval,PAGE_SHIFT);
+ return;
+ }
+ if (trp = match_tr(d,address)) {
+ // FIXME address had better be pre-validated on insert
+ pteval = translate_domain_pte(trp->page_flags,address,trp->itir);
+ vcpu_itc_no_srlz(d,is_data?2:1,address,pteval,(trp->itir>>2)&0x3f);
+ return;
+ }
+ vector = is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR;
+ if (handle_lazy_cover(d, isr, regs)) return;
+if (!(address>>61)) { printf("ia64_do_page_fault: @%p???, iip=%p, itc=%p (spinning...)\n",address,iip,ia64_get_itc()); while(1); }
+ if ((isr & IA64_ISR_SP)
+ || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH))
+ {
+ /*
+ * This fault was due to a speculative load or lfetch.fault, set the "ed"
+ * bit in the psr to ensure forward progress. (Target register will get a
+ * NaT for ld.s, lfetch will be canceled.)
+ */
+ ia64_psr(regs)->ed = 1;
+ return;
+ }
+ reflect_interruption(address, isr, itir, regs, vector);
+}
+
+void
+ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
+ unsigned long iim, unsigned long itir, unsigned long arg5,
+ unsigned long arg6, unsigned long arg7, unsigned long stack)
+{
+ struct pt_regs *regs = (struct pt_regs *) &stack;
+ unsigned long code, error = isr;
+ char buf[128];
+ int result, sig;
+ static const char *reason[] = {
+ "IA-64 Illegal Operation fault",
+ "IA-64 Privileged Operation fault",
+ "IA-64 Privileged Register fault",
+ "IA-64 Reserved Register/Field fault",
+ "Disabled Instruction Set Transition fault",
+ "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault",
+ "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12",
+ "Unknown fault 13", "Unknown fault 14", "Unknown fault 15"
+ };
+#if 0
+printf("ia64_fault, vector=0x%p, ifa=%p, iip=%p, ipsr=%p, isr=%p\n",
+ vector, ifa, regs->cr_iip, regs->cr_ipsr, isr);
+#endif
+
+ if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) {
+ /*
+ * This fault was due to lfetch.fault, set "ed" bit in the psr to cancel
+ * the lfetch.
+ */
+ ia64_psr(regs)->ed = 1;
+ printf("ia64_fault: handled lfetch.fault\n");
+ return;
+ }
+
+ switch (vector) {
+ case 24: /* General Exception */
+ code = (isr >> 4) & 0xf;
+ sprintf(buf, "General Exception: %s%s", reason[code],
+ (code == 3) ? ((isr & (1UL << 37))
+ ? " (RSE access)" : " (data access)") : "");
+ if (code == 8) {
+# ifdef CONFIG_IA64_PRINT_HAZARDS
+ printk("%s[%d]: possible hazard @ ip=%016lx (pr = %016lx)\n",
+ current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri,
+ regs->pr);
+# endif
+ printf("ia64_fault: returning on hazard\n");
+ return;
+ }
+ break;
+
+ case 25: /* Disabled FP-Register */
+ if (isr & 2) {
+ //disabled_fph_fault(regs);
+ //return;
+ }
+ sprintf(buf, "Disabled FPL fault---not supposed to happen!");
+ break;
+
+ case 26: /* NaT Consumption */
+ if (user_mode(regs)) {
+ void *addr;
+
+ if (((isr >> 4) & 0xf) == 2) {
+ /* NaT page consumption */
+ //sig = SIGSEGV;
+ //code = SEGV_ACCERR;
+ addr = (void *) ifa;
+ } else {
+ /* register NaT consumption */
+ //sig = SIGILL;
+ //code = ILL_ILLOPN;
+ addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+ }
+ //siginfo.si_signo = sig;
+ //siginfo.si_code = code;
+ //siginfo.si_errno = 0;
+ //siginfo.si_addr = addr;
+ //siginfo.si_imm = vector;
+ //siginfo.si_flags = __ISR_VALID;
+ //siginfo.si_isr = isr;
+ //force_sig_info(sig, &siginfo, current);
+ //return;
+ } //else if (ia64_done_with_exception(regs))
+ //return;
+ sprintf(buf, "NaT consumption");
+ break;
+
+ case 31: /* Unsupported Data Reference */
+ if (user_mode(regs)) {
+ //siginfo.si_signo = SIGILL;
+ //siginfo.si_code = ILL_ILLOPN;
+ //siginfo.si_errno = 0;
+ //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+ //siginfo.si_imm = vector;
+ //siginfo.si_flags = __ISR_VALID;
+ //siginfo.si_isr = isr;
+ //force_sig_info(SIGILL, &siginfo, current);
+ //return;
+ }
+ sprintf(buf, "Unsupported data reference");
+ break;
+
+ case 29: /* Debug */
+ case 35: /* Taken Branch Trap */
+ case 36: /* Single Step Trap */
+ //if (fsys_mode(current, regs)) {}
+ switch (vector) {
+ case 29:
+ //siginfo.si_code = TRAP_HWBKPT;
+#ifdef CONFIG_ITANIUM
+ /*
+ * Erratum 10 (IFA may contain incorrect address) now has
+ * "NoFix" status. There are no plans for fixing this.
+ */
+ if (ia64_psr(regs)->is == 0)
+ ifa = regs->cr_iip;
+#endif
+ break;
+ case 35: ifa = 0; break;
+ case 36: ifa = 0; break;
+ //case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break;
+ //case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break;
+ }
+ //siginfo.si_signo = SIGTRAP;
+ //siginfo.si_errno = 0;
+ //siginfo.si_addr = (void *) ifa;
+ //siginfo.si_imm = 0;
+ //siginfo.si_flags = __ISR_VALID;
+ //siginfo.si_isr = isr;
+ //force_sig_info(SIGTRAP, &siginfo, current);
+ //return;
+
+ case 32: /* fp fault */
+ case 33: /* fp trap */
+ //result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr);
+ if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) {
+ //siginfo.si_signo = SIGFPE;
+ //siginfo.si_errno = 0;
+ //siginfo.si_code = FPE_FLTINV;
+ //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+ //siginfo.si_flags = __ISR_VALID;
+ //siginfo.si_isr = isr;
+ //siginfo.si_imm = 0;
+ //force_sig_info(SIGFPE, &siginfo, current);
+ }
+ //return;
+ sprintf(buf, "FP fault/trap");
+ break;
+
+ case 34:
+ if (isr & 0x2) {
+ /* Lower-Privilege Transfer Trap */
+ /*
+ * Just clear PSR.lp and then return immediately: all the
+ * interesting work (e.g., signal delivery is done in the kernel
+ * exit path).
+ */
+ //ia64_psr(regs)->lp = 0;
+ //return;
+ sprintf(buf, "Lower-Privilege Transfer trap");
+ } else {
+ /* Unimplemented Instr. Address Trap */
+ if (user_mode(regs)) {
+ //siginfo.si_signo = SIGILL;
+ //siginfo.si_code = ILL_BADIADDR;
+ //siginfo.si_errno = 0;
+ //siginfo.si_flags = 0;
+ //siginfo.si_isr = 0;
+ //siginfo.si_imm = 0;
+ //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+ //force_sig_info(SIGILL, &siginfo, current);
+ //return;
+ }
+ sprintf(buf, "Unimplemented Instruction Address fault");
+ }
+ break;
+
+ case 45:
+ printk(KERN_ERR "Unexpected IA-32 exception (Trap 45)\n");
+ printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n",
+ regs->cr_iip, ifa, isr);
+ //force_sig(SIGSEGV, current);
+ break;
+
+ case 46:
+ printk(KERN_ERR "Unexpected IA-32 intercept trap (Trap 46)\n");
+ printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n",
+ regs->cr_iip, ifa, isr, iim);
+ //force_sig(SIGSEGV, current);
+ return;
+
+ case 47:
+ sprintf(buf, "IA-32 Interruption Fault (int 0x%lx)", isr >> 16);
+ break;
+
+ default:
+ sprintf(buf, "Fault %lu", vector);
+ break;
+ }
+ //die_if_kernel(buf, regs, error);
+printk("ia64_fault: %s: reflecting\n",buf);
+reflect_interruption(ifa,isr,iim,regs,IA64_GENEX_VECTOR);
+//while(1);
+ //force_sig(SIGILL, current);
+}
+
+unsigned long running_on_sim = 0;
+
+void
+do_ssc(unsigned long ssc, struct pt_regs *regs)
+{
+ extern unsigned long lookup_domain_mpa(struct domain *,unsigned long);
+ unsigned long arg0, arg1, arg2, arg3, retval;
+ char buf[2];
+/**/ static int last_fd, last_count; // FIXME FIXME FIXME
+/**/ // BROKEN FOR MULTIPLE DOMAINS & SMP
+/**/ struct ssc_disk_stat { int fd; unsigned count;} *stat, last_stat;
+ extern unsigned long vcpu_verbose, privop_trace;
+
+ arg0 = vcpu_get_gr(current,32);
+ switch(ssc) {
+ case SSC_PUTCHAR:
+ buf[0] = arg0;
+ buf[1] = '\0';
+ printf(buf);
+ break;
+ case SSC_GETCHAR:
+ retval = ia64_ssc(0,0,0,0,ssc);
+ vcpu_set_gr(current,8,retval);
+ break;
+ case SSC_WAIT_COMPLETION:
+ if (arg0) { // metaphysical address
+
+ arg0 = translate_domain_mpaddr(arg0);
+/**/ stat = (struct ssc_disk_stat *)__va(arg0);
+///**/ if (stat->fd == last_fd) stat->count = last_count;
+/**/ stat->count = last_count;
+//if (last_count >= PAGE_SIZE) printf("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count);
+///**/ retval = ia64_ssc(arg0,0,0,0,ssc);
+/**/ retval = 0;
+ }
+ else retval = -1L;
+ vcpu_set_gr(current,8,retval);
+ break;
+ case SSC_OPEN:
+ arg1 = vcpu_get_gr(current,33); // access rights
+if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring...)\n"); arg0 = 0; }
+ if (arg0) { // metaphysical address
+ arg0 = translate_domain_mpaddr(arg0);
+ retval = ia64_ssc(arg0,arg1,0,0,ssc);
+ }
+ else retval = -1L;
+ vcpu_set_gr(current,8,retval);
+ break;
+ case SSC_WRITE:
+ case SSC_READ:
+//if (ssc == SSC_WRITE) printf("DOING AN SSC_WRITE\n");
+ arg1 = vcpu_get_gr(current,33);
+ arg2 = vcpu_get_gr(current,34);
+ arg3 = vcpu_get_gr(current,35);
+ if (arg2) { // metaphysical address of descriptor
+ struct ssc_disk_req *req;
+ unsigned long mpaddr, paddr;
+ long len;
+
+ arg2 = translate_domain_mpaddr(arg2);
+ req = (struct disk_req *)__va(arg2);
+ req->len &= 0xffffffffL; // avoid strange bug
+ len = req->len;
+/**/ last_fd = arg1;
+/**/ last_count = len;
+ mpaddr = req->addr;
+//if (last_count >= PAGE_SIZE) printf("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len);
+ retval = 0;
+ if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & PAGE_MASK)) {
+ // do partial page first
+ req->addr = translate_domain_mpaddr(mpaddr);
+ req->len = PAGE_SIZE - (req->addr & ~PAGE_MASK);
+ len -= req->len; mpaddr += req->len;
+ retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
+ arg3 += req->len; // file offset
+/**/ last_stat.fd = last_fd;
+/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
+//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval);
+ }
+ if (retval >= 0) while (len > 0) {
+ req->addr = translate_domain_mpaddr(mpaddr);
+ req->len = (len > PAGE_SIZE) ? PAGE_SIZE : len;
+ len -= PAGE_SIZE; mpaddr += PAGE_SIZE;
+ retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
+ arg3 += req->len; // file offset
+// TEMP REMOVED AGAIN arg3 += req->len; // file offset
+/**/ last_stat.fd = last_fd;
+/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
+//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)=%x ",req->addr,req->len,retval);
+ }
+ // set it back to the original value
+ req->len = last_count;
+ }
+ else retval = -1L;
+ vcpu_set_gr(current,8,retval);
+//if (last_count >= PAGE_SIZE) printf("retval=%x\n",retval);
+ break;
+ case SSC_CONNECT_INTERRUPT:
+ arg1 = vcpu_get_gr(current,33);
+ arg2 = vcpu_get_gr(current,34);
+ arg3 = vcpu_get_gr(current,35);
+ if (!running_on_sim) { printf("SSC_CONNECT_INTERRUPT, not implemented on hardware. (ignoring...)\n"); break; }
+ (void)ia64_ssc(arg0,arg1,arg2,arg3,ssc);
+ break;
+ case SSC_NETDEV_PROBE:
+ vcpu_set_gr(current,8,-1L);
+ break;
+ default:
+ printf("ia64_handle_break: bad ssc code %lx\n",ssc);
+ break;
+ }
+ vcpu_increment_iip(current);
+}
+
+void fooefi(void) {}
+
+void
+ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim)
+{
+ static int first_time = 1;
+ struct domain *d = (struct domain *) current;
+ extern unsigned long running_on_sim;
+
+ if (first_time) {
+ if (platform_is_hp_ski()) running_on_sim = 1;
+ else running_on_sim = 0;
+ first_time = 0;
+ }
+ if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant
+ if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs);
+ else do_ssc(vcpu_get_gr(current,36), regs);
+ }
+ else if (iim == d->breakimm) {
+ struct ia64_sal_retval x;
+ switch (regs->r2) {
+ case FW_HYPERCALL_PAL_CALL:
+ //printf("*** PAL hypercall: index=%d\n",regs->r28);
+ //FIXME: This should call a C routine
+ x = pal_emulator_static(regs->r28);
+ regs->r8 = x.status; regs->r9 = x.v0;
+ regs->r10 = x.v1; regs->r11 = x.v2;
+ break;
+ case FW_HYPERCALL_SAL_CALL:
+ x = sal_emulator(vcpu_get_gr(d,32),vcpu_get_gr(d,33),
+ vcpu_get_gr(d,34),vcpu_get_gr(d,35),
+ vcpu_get_gr(d,36),vcpu_get_gr(d,37),
+ vcpu_get_gr(d,38),vcpu_get_gr(d,39));
+ regs->r8 = x.status; regs->r9 = x.v0;
+ regs->r10 = x.v1; regs->r11 = x.v2;
+ break;
+ case FW_HYPERCALL_EFI_RESET_SYSTEM:
+ printf("efi.reset_system called ");
+ if (current == dom0) {
+ printf("(by dom0)\n ");
+ (*efi.reset_system)(EFI_RESET_WARM,0,0,NULL);
+ }
+ printf("(not supported for non-0 domain)\n");
+ regs->r8 = EFI_UNSUPPORTED;
+ break;
+ case FW_HYPERCALL_EFI_GET_TIME:
+ {
+ unsigned long *tv, *tc;
+ fooefi();
+ tv = vcpu_get_gr(d,32);
+ tc = vcpu_get_gr(d,33);
+ //printf("efi_get_time(%p,%p) called...",tv,tc);
+ tv = __va(translate_domain_mpaddr(tv));
+ if (tc) tc = __va(translate_domain_mpaddr(tc));
+ regs->r8 = (*efi.get_time)(tv,tc);
+ //printf("and returns %lx\n",regs->r8);
+ }
+ break;
+ case FW_HYPERCALL_EFI_SET_TIME:
+ case FW_HYPERCALL_EFI_GET_WAKEUP_TIME:
+ case FW_HYPERCALL_EFI_SET_WAKEUP_TIME:
+ // FIXME: need fixes in efi.h from 2.6.9
+ case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP:
+ // FIXME: WARNING!! IF THIS EVER GETS IMPLEMENTED
+ // SOME OF THE OTHER EFI EMULATIONS WILL CHANGE AS
+ // POINTER ARGUMENTS WILL BE VIRTUAL!!
+ case FW_HYPERCALL_EFI_GET_VARIABLE:
+ // FIXME: need fixes in efi.h from 2.6.9
+ case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE:
+ case FW_HYPERCALL_EFI_SET_VARIABLE:
+ case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT:
+ // FIXME: need fixes in efi.h from 2.6.9
+ regs->r8 = EFI_UNSUPPORTED;
+ break;
+ }
+ vcpu_increment_iip(current);
+ }
+ else reflect_interruption(ifa,isr,iim,regs,IA64_BREAK_VECTOR);
+}
+
+void
+ia64_handle_privop (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long itir)
+{
+ IA64FAULT vector;
+ struct domain *d = (struct domain *) current;
+ // FIXME: no need to pass itir in to this routine as we need to
+ // compute the virtual itir anyway (based on domain's RR.ps)
+ // AND ACTUALLY reflect_interruption doesn't use it anyway!
+ itir = vcpu_get_itir_on_fault(d,ifa);
+ vector = priv_emulate((struct domain *)current,regs,isr);
+ if (vector == IA64_RETRY) {
+ reflect_interruption(ifa,isr,itir,regs,
+ IA64_ALT_DATA_TLB_VECTOR | IA64_FORCED_IFA);
+ }
+ else if (vector != IA64_NO_FAULT && vector != IA64_RFI_IN_PROGRESS) {
+ reflect_interruption(ifa,isr,itir,regs,vector);
+ }
+}
+
+#define INTR_TYPE_MAX 10
+UINT64 int_counts[INTR_TYPE_MAX];
+
+void
+ia64_handle_reflection (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim, unsigned long vector)
+{
+ extern unsigned long vcpu_get_itir_on_fault(struct domain *vcpu, UINT64 ifa);
+ struct domain *d = (struct domain *) current;
+ unsigned long check_lazy_cover = 0;
+ unsigned long psr = regs->cr_ipsr;
+ unsigned long itir = vcpu_get_itir_on_fault(d,ifa);
+
+ if (!(psr & IA64_PSR_CPL)) {
+ printf("ia64_handle_reflection: reflecting with priv=0!!\n");
+ while(1);
+ }
+ // FIXME: no need to pass itir in to this routine as we need to
+ // compute the virtual itir anyway (based on domain's RR.ps)
+ // AND ACTUALLY reflect_interruption doesn't use it anyway!
+ itir = vcpu_get_itir_on_fault(d,ifa);
+ switch(vector) {
+ case 8:
+ vector = IA64_DIRTY_BIT_VECTOR; break;
+ case 9:
+ vector = IA64_INST_ACCESS_BIT_VECTOR; break;
+ case 10:
+ check_lazy_cover = 1;
+ vector = IA64_DATA_ACCESS_BIT_VECTOR; break;
+ case 22:
+ vector = IA64_INST_ACCESS_RIGHTS_VECTOR; break;
+ case 23:
+ check_lazy_cover = 1;
+ vector = IA64_DATA_ACCESS_RIGHTS_VECTOR; break;
+ case 25:
+ vector = IA64_DISABLED_FPREG_VECTOR; break;
+ case 26:
+printf("*** NaT fault... attempting to handle as privop\n");
+ vector = priv_emulate(d,regs,isr);
+ if (vector == IA64_NO_FAULT) {
+printf("*** Handled privop masquerading as NaT fault\n");
+ return;
+ }
+ vector = IA64_NAT_CONSUMPTION_VECTOR; break;
+ case 27:
+//printf("*** Handled speculation vector, itc=%lx!\n",ia64_get_itc());
+ itir = iim;
+ vector = IA64_SPECULATION_VECTOR; break;
+ case 30:
+ // FIXME: Should we handle unaligned refs in Xen??
+ vector = IA64_UNALIGNED_REF_VECTOR; break;
+ default:
+ printf("ia64_handle_reflection: unhandled vector=0x%lx\n",vector);
+ while(vector);
+ return;
+ }
+ if (check_lazy_cover && handle_lazy_cover(d, isr, regs)) return;
+ reflect_interruption(ifa,isr,itir,regs,vector);
+}
--- /dev/null
+/*
+ * Region register and region id management
+ *
+ * Copyright (C) 2001-2004 Hewlett-Packard Co.
+ * Dan Magenheimer (dan.magenheimer@hp.com
+ * Bret Mckee (bret.mckee@hp.com)
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <asm/page.h>
+#include <asm/regionreg.h>
+#include <asm/vhpt.h>
+
+
+#define IA64_MIN_IMPL_RID_BITS (IA64_MIN_IMPL_RID_MSB+1)
+#define IA64_MAX_IMPL_RID_BITS 24
+
+#define MIN_RIDS (1 << IA64_MIN_IMPL_RID_BITS)
+#define MIN_RID_MAX (MIN_RIDS - 1)
+#define MIN_RID_MASK (MIN_RIDS - 1)
+#define MAX_RIDS (1 << (IA64_MAX_IMPL_RID_BITS))
+#define MAX_RID (MAX_RIDS - 1)
+#define MAX_RID_BLOCKS (1 << (IA64_MAX_IMPL_RID_BITS-IA64_MIN_IMPL_RID_BITS))
+#define RIDS_PER_RIDBLOCK MIN_RIDS
+
+// This is the one global memory representation of the default Xen region reg
+ia64_rr xen_rr;
+
+#if 0
+// following already defined in include/asm-ia64/gcc_intrin.h
+// it should probably be ifdef'd out from there to ensure all region
+// register usage is encapsulated in this file
+static inline unsigned long
+ia64_get_rr (unsigned long rr)
+{
+ unsigned long r;
+ __asm__ __volatile__ (";;mov %0=rr[%1];;":"=r"(r):"r"(rr):"memory");
+ return r;
+}
+
+static inline void
+ia64_set_rr (unsigned long rr, unsigned long rrv)
+{
+ __asm__ __volatile__ (";;mov rr[%0]=%1;;"::"r"(rr),"r"(rrv):"memory");
+}
+#endif
+
+// use this to allocate a rid out of the "Xen reserved rid block"
+unsigned long allocate_reserved_rid(void)
+{
+ static unsigned long currentrid = XEN_DEFAULT_RID;
+ unsigned long t = currentrid;
+
+ unsigned long max = RIDS_PER_RIDBLOCK;
+
+ if (++currentrid >= max) return(-1UL);
+ return t;
+}
+
+
+// returns -1 if none available
+unsigned long allocate_metaphysical_rid(void)
+{
+ unsigned long rid = allocate_reserved_rid();
+}
+
+int deallocate_metaphysical_rid(unsigned long rid)
+{
+ // fix this when the increment allocation mechanism is fixed.
+ return 1;
+}
+
+
+void init_rr(void)
+{
+ xen_rr.rrval = 0;
+ xen_rr.ve = 0;
+ xen_rr.rid = allocate_reserved_rid();
+ xen_rr.ps = PAGE_SHIFT;
+
+ printf("initialized xen_rr.rid=0x%lx\n", xen_rr.rid);
+}
+
+/*************************************
+ Region Block setup/management
+*************************************/
+
+static int implemented_rid_bits = 0;
+static struct domain *ridblock_owner[MAX_RID_BLOCKS] = { 0 };
+
+void get_impl_rid_bits(void)
+{
+ // FIXME (call PAL)
+//#ifdef CONFIG_MCKINLEY
+ implemented_rid_bits = IA64_MAX_IMPL_RID_BITS;
+//#else
+//#error "rid ranges won't work on Merced"
+//#endif
+ if (implemented_rid_bits <= IA64_MIN_IMPL_RID_BITS ||
+ implemented_rid_bits > IA64_MAX_IMPL_RID_BITS)
+ BUG();
+}
+
+
+/*
+ * Allocate a power-of-two-sized chunk of region id space -- one or more
+ * "rid blocks"
+ */
+int allocate_rid_range(struct domain *d, unsigned long ridbits)
+{
+ int i, j, n_rid_blocks;
+
+ if (implemented_rid_bits == 0) get_impl_rid_bits();
+
+ if (ridbits >= IA64_MAX_IMPL_RID_BITS)
+ ridbits = IA64_MAX_IMPL_RID_BITS - 1;
+
+ if (ridbits < IA64_MIN_IMPL_RID_BITS)
+ ridbits = IA64_MIN_IMPL_RID_BITS;
+
+ // convert to rid_blocks and find one
+ n_rid_blocks = ridbits - IA64_MIN_IMPL_RID_BITS + 1;
+
+ // skip over block 0, reserved for "meta-physical mappings (and Xen)"
+ for (i = n_rid_blocks; i < MAX_RID_BLOCKS; i += n_rid_blocks) {
+ if (ridblock_owner[i] == NULL) {
+ for (j = i; j < i + n_rid_blocks; ++j) {
+ if (ridblock_owner[j]) break;
+ }
+ if (ridblock_owner[j] == NULL) break;
+ }
+ }
+
+ if (i >= MAX_RID_BLOCKS) return 0;
+
+ // found an unused block:
+ // (i << min_rid_bits) <= rid < ((i + n) << min_rid_bits)
+ // mark this block as owned
+ for (j = i; j < i + n_rid_blocks; ++j) ridblock_owner[j] = d;
+
+ // setup domain struct
+ d->rid_bits = ridbits;
+ d->starting_rid = i << IA64_MIN_IMPL_RID_BITS;
+ d->ending_rid = (i+n_rid_blocks) << IA64_MIN_IMPL_RID_BITS;
+
+ return 1;
+}
+
+
+int deallocate_rid_range(struct domain *d)
+{
+ int i;
+ int rid_block_end = d->ending_rid >> IA64_MIN_IMPL_RID_BITS;
+ int rid_block_start = d->starting_rid >> IA64_MIN_IMPL_RID_BITS;
+
+ return 1; // KLUDGE ALERT
+ //
+ // not all domains will have allocated RIDs (physical mode loaders for instance)
+ //
+ if (d->rid_bits == 0) return 1;
+
+#ifdef DEBUG
+ for (i = rid_block_start; i < rid_block_end; ++i) {
+ ASSERT(ridblock_owner[i] == d);
+ }
+#endif
+
+ for (i = rid_block_start; i < rid_block_end; ++i)
+ ridblock_owner[i] = NULL;
+
+ d->rid_bits = 0;
+ d->starting_rid = 0;
+ d->ending_rid = 0;
+ return 1;
+}
+
+
+// This function is purely for performance... apparently scrambling
+// bits in the region id makes for better hashing, which means better
+// use of the VHPT, which means better performance
+// Note that the only time a RID should be mangled is when it is stored in
+// a region register; anytime it is "viewable" outside of this module,
+// it should be unmangled
+
+//This appears to work in Xen... turn it on later so no complications yet
+//#define CONFIG_MANGLE_RIDS
+#ifdef CONFIG_MANGLE_RIDS
+static inline unsigned long
+vmMangleRID(unsigned long RIDVal)
+{
+ union bits64 { unsigned char bytes[4]; unsigned long uint; };
+
+ union bits64 t;
+ unsigned char tmp;
+
+ t.uint = RIDVal;
+ tmp = t.bytes[1];
+ t.bytes[1] = t.bytes[3];
+ t.bytes[3] = tmp;
+
+ return t.uint;
+}
+
+// since vmMangleRID is symmetric, use it for unmangling also
+#define vmUnmangleRID(x) vmMangleRID(x)
+#else
+// no mangling/unmangling
+#define vmMangleRID(x) (x)
+#define vmUnmangleRID(x) (x)
+#endif
+
+static inline void
+set_rr_no_srlz(unsigned long rr, unsigned long rrval)
+{
+ ia64_set_rr(rr, vmMangleRID(rrval));
+}
+
+void
+set_rr(unsigned long rr, unsigned long rrval)
+{
+ ia64_set_rr(rr, vmMangleRID(rrval));
+ ia64_srlz_d();
+}
+
+unsigned long
+get_rr(unsigned long rr)
+{
+ return vmUnmangleRID(ia64_get_rr(rr));
+}
+
+static inline int validate_page_size(unsigned long ps)
+{
+ switch(ps) {
+ case 12: case 13: case 14: case 16: case 18:
+ case 20: case 22: case 24: case 26: case 28:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+// validates and changes a single region register
+// in the currently executing domain
+// Passing a value of -1 is a (successful) no-op
+// NOTE: DOES NOT SET VCPU's rrs[x] value!!
+int set_one_rr(unsigned long rr, unsigned long val)
+{
+ struct domain *d = current;
+ unsigned long rreg = REGION_NUMBER(rr);
+ ia64_rr rrv, newrrv, memrrv;
+ unsigned long newrid;
+
+ if (val == -1) return 1;
+
+ rrv.rrval = val;
+ newrrv.rrval = 0;
+ newrid = d->starting_rid + rrv.rid;
+
+ if (newrid > d->ending_rid) return 0;
+
+ memrrv.rrval = rrv.rrval;
+ if (rreg == 7) {
+ newrrv.rid = newrid;
+ newrrv.ve = VHPT_ENABLED_REGION_7;
+ newrrv.ps = IA64_GRANULE_SHIFT;
+ ia64_new_rr7(vmMangleRID(newrrv.rrval));
+ }
+ else {
+ newrrv.rid = newrid;
+ // FIXME? region 6 needs to be uncached for EFI to work
+ if (rreg == 6) newrrv.ve = VHPT_ENABLED_REGION_7;
+ else newrrv.ve = VHPT_ENABLED_REGION_0_TO_6;
+ newrrv.ps = PAGE_SHIFT;
+ set_rr(rr,newrrv.rrval);
+ }
+ return 1;
+}
+
+// set rr0 to the passed rid (for metaphysical mode so don't use domain offset
+int set_metaphysical_rr(unsigned long rr, unsigned long rid)
+{
+ ia64_rr rrv;
+
+ rrv.rrval = 0;
+ rrv.rid = rid;
+ rrv.ps = PAGE_SHIFT;
+// rrv.ve = 1; FIXME: TURN ME BACK ON WHEN VHPT IS WORKING
+ rrv.ve = 0;
+ set_rr(rr,rrv.rrval);
+}
+
+// validates/changes region registers 0-6 in the currently executing domain
+// Note that this is the one and only SP API (other than executing a privop)
+// for a domain to use to change region registers
+int set_all_rr( u64 rr0, u64 rr1, u64 rr2, u64 rr3,
+ u64 rr4, u64 rr5, u64 rr6, u64 rr7)
+{
+ if (!set_one_rr(0x0000000000000000L, rr0)) return 0;
+ if (!set_one_rr(0x2000000000000000L, rr1)) return 0;
+ if (!set_one_rr(0x4000000000000000L, rr2)) return 0;
+ if (!set_one_rr(0x6000000000000000L, rr3)) return 0;
+ if (!set_one_rr(0x8000000000000000L, rr4)) return 0;
+ if (!set_one_rr(0xa000000000000000L, rr5)) return 0;
+ if (!set_one_rr(0xc000000000000000L, rr6)) return 0;
+ if (!set_one_rr(0xe000000000000000L, rr7)) return 0;
+ return 1;
+}
+
+void init_all_rr(struct domain *d)
+{
+ ia64_rr rrv;
+
+ rrv.rrval = 0;
+ rrv.rid = d->metaphysical_rid;
+ rrv.ps = PAGE_SHIFT;
+ rrv.ve = 1;
+ d->shared_info->arch.rrs[0] = -1;
+ d->shared_info->arch.rrs[1] = rrv.rrval;
+ d->shared_info->arch.rrs[2] = rrv.rrval;
+ d->shared_info->arch.rrs[3] = rrv.rrval;
+ d->shared_info->arch.rrs[4] = rrv.rrval;
+ d->shared_info->arch.rrs[5] = rrv.rrval;
+ d->shared_info->arch.rrs[6] = rrv.rrval;
+// d->shared_info->arch.rrs[7] = rrv.rrval;
+}
+
+
+/* XEN/ia64 INTERNAL ROUTINES */
+
+unsigned long physicalize_rid(struct domain *d, unsigned long rid)
+{
+ ia64_rr rrv;
+
+ rrv.rrval = rid;
+ rrv.rid += d->starting_rid;
+ return rrv.rrval;
+}
+
+unsigned long
+virtualize_rid(struct domain *d, unsigned long rid)
+{
+ ia64_rr rrv;
+
+ rrv.rrval = rid;
+ rrv.rid -= d->starting_rid;
+ return rrv.rrval;
+}
+
+// loads a thread's region register (0-6) state into
+// the real physical region registers. Returns the
+// (possibly mangled) bits to store into rr7
+// iff it is different than what is currently in physical
+// rr7 (because we have to to assembly and physical mode
+// to change rr7). If no change to rr7 is required, returns 0.
+//
+unsigned long load_region_regs(struct domain *d)
+{
+ unsigned long rr0, rr1,rr2, rr3, rr4, rr5, rr6;
+ unsigned long oldrr7, newrr7;
+ // TODO: These probably should be validated
+
+ if (d->metaphysical_mode) {
+ ia64_rr rrv;
+
+ rrv.rid = d->metaphysical_rid;
+ rrv.ps = PAGE_SHIFT;
+ rrv.ve = 1;
+ rr0 = rr1 = rr2 = rr3 = rr4 = rr5 = rr6 = newrr7 = rrv.rrval;
+ }
+ else {
+ rr0 = physicalize_rid(d, d->shared_info->arch.rrs[0]);
+ rr1 = physicalize_rid(d, d->shared_info->arch.rrs[1]);
+ rr2 = physicalize_rid(d, d->shared_info->arch.rrs[2]);
+ rr3 = physicalize_rid(d, d->shared_info->arch.rrs[3]);
+ rr4 = physicalize_rid(d, d->shared_info->arch.rrs[4]);
+ rr5 = physicalize_rid(d, d->shared_info->arch.rrs[5]);
+ rr6 = physicalize_rid(d, d->shared_info->arch.rrs[6]);
+ newrr7 = physicalize_rid(d, d->shared_info->arch.rrs[7]);
+ }
+
+ set_rr_no_srlz(0x0000000000000000L, rr0);
+ set_rr_no_srlz(0x2000000000000000L, rr1);
+ set_rr_no_srlz(0x4000000000000000L, rr2);
+ set_rr_no_srlz(0x6000000000000000L, rr3);
+ set_rr_no_srlz(0x8000000000000000L, rr4);
+ set_rr_no_srlz(0xa000000000000000L, rr5);
+ set_rr_no_srlz(0xc000000000000000L, rr6);
+ ia64_srlz_d();
+ oldrr7 = get_rr(0xe000000000000000L);
+ if (oldrr7 != newrr7) {
+ newrr7 = (newrr7 & ~0xff) | (PAGE_SHIFT << 2) | 1;
+ return vmMangleRID(newrr7);
+ }
+ else return 0;
+}
--- /dev/null
+/*
+ * Virtualized CPU functions
+ *
+ * Copyright (C) 2004 Hewlett-Packard Co.
+ * Dan Magenheimer (dan.magenheimer@hp.com)
+ *
+ */
+
+#include <linux/sched.h>
+#include <asm/ia64_int.h>
+#include <asm/vcpu.h>
+#include <asm/regionreg.h>
+#include <asm/tlb.h>
+#include <asm/processor.h>
+#include <asm/delay.h>
+
+typedef union {
+ struct ia64_psr;
+ unsigned long i64;
+} PSR;
+
+//typedef struct pt_regs REGS;
+//typedef struct domain VCPU;
+
+// this def for vcpu_regs won't work if kernel stack is present
+#define vcpu_regs(vcpu) ((struct pt_regs *) vcpu->regs)
+#define PSCB(x) x->shared_info->arch
+
+#define TRUE 1
+#define FALSE 0
+#define IA64_PTA_SZ_BIT 2
+#define IA64_PTA_VF_BIT 8
+#define IA64_PTA_BASE_BIT 15
+#define IA64_PTA_LFMT (1UL << IA64_PTA_VF_BIT)
+#define IA64_PTA_SZ(x) (x##UL << IA64_PTA_SZ_BIT)
+
+#define STATIC
+
+unsigned long vcpu_verbose = 0;
+#define verbose(a...) do {if (vcpu_verbose) printf(a);} while(0)
+
+/**************************************************************************
+ VCPU general register access routines
+**************************************************************************/
+
+UINT64
+vcpu_get_gr(VCPU *vcpu, unsigned reg)
+{
+ REGS *regs = vcpu_regs(vcpu);
+ UINT64 val;
+
+ if (!reg) return 0;
+ getreg(reg,&val,0,regs); // FIXME: handle NATs later
+ return val;
+}
+
+// returns:
+// IA64_ILLOP_FAULT if the register would cause an Illegal Operation fault
+// IA64_NO_FAULT otherwise
+IA64FAULT
+vcpu_set_gr(VCPU *vcpu, unsigned reg, UINT64 value)
+{
+ REGS *regs = vcpu_regs(vcpu);
+ long sof = (regs->cr_ifs) & 0x7f;
+
+ if (!reg) return IA64_ILLOP_FAULT;
+ if (reg >= sof + 32) return IA64_ILLOP_FAULT;
+ setreg(reg,value,0,regs); // FIXME: handle NATs later
+ return IA64_NO_FAULT;
+}
+
+/**************************************************************************
+ VCPU privileged application register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_set_ar(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+ if (reg == 44) return (vcpu_set_itc(vcpu,val));
+ if (reg == 27) return (IA64_ILLOP_FAULT);
+ if (reg > 7) return (IA64_ILLOP_FAULT);
+ PSCB(vcpu).krs[reg] = val;
+#if 0
+// for now, privify kr read's so all kr accesses are privileged
+ switch (reg) {
+ case 0: asm volatile ("mov ar.k0=%0" :: "r"(val)); break;
+ case 1: asm volatile ("mov ar.k1=%0" :: "r"(val)); break;
+ case 2: asm volatile ("mov ar.k2=%0" :: "r"(val)); break;
+ case 3: asm volatile ("mov ar.k3=%0" :: "r"(val)); break;
+ case 4: asm volatile ("mov ar.k4=%0" :: "r"(val)); break;
+ case 5: asm volatile ("mov ar.k5=%0" :: "r"(val)); break;
+ case 6: asm volatile ("mov ar.k6=%0" :: "r"(val)); break;
+ case 7: asm volatile ("mov ar.k7=%0" :: "r"(val)); break;
+ case 27: asm volatile ("mov ar.cflg=%0" :: "r"(val)); break;
+ }
+#endif
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *val)
+{
+ if (reg > 7) return (IA64_ILLOP_FAULT);
+ *val = PSCB(vcpu).krs[reg];
+ return IA64_NO_FAULT;
+}
+
+/**************************************************************************
+ VCPU processor status register access routines
+**************************************************************************/
+
+void vcpu_set_metaphysical_mode(VCPU *vcpu, BOOLEAN newmode)
+{
+ /* only do something if mode changes */
+ if (!!newmode ^ !!vcpu->metaphysical_mode) {
+ if (newmode) set_metaphysical_rr(0,vcpu->metaphysical_rid);
+ else if (PSCB(vcpu).rrs[0] != -1)
+ set_one_rr(0, PSCB(vcpu).rrs[0]);
+ vcpu->metaphysical_mode = newmode;
+ }
+}
+
+IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24)
+{
+ struct ia64_psr psr, imm, *ipsr;
+ REGS *regs = vcpu_regs(vcpu);
+
+ // TODO: All of these bits need to be virtualized
+ // TODO: Only allowed for current vcpu
+ __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory");
+ ipsr = (struct ia64_psr *)®s->cr_ipsr;
+ imm = *(struct ia64_psr *)&imm24;
+ // interrupt flag
+ if (imm.i) PSCB(vcpu).interrupt_delivery_enabled = 0;
+ if (imm.ic) PSCB(vcpu).interrupt_collection_enabled = 0;
+ // interrupt collection flag
+ //if (imm.ic) PSCB(vcpu).interrupt_delivery_enabled = 0;
+ // just handle psr.up and psr.pp for now
+ if (imm24 & ~(IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP
+ | IA64_PSR_I | IA64_PSR_IC | IA64_PSR_DT
+ | IA64_PSR_DFL | IA64_PSR_DFH))
+ return (IA64_ILLOP_FAULT);
+ if (imm.dfh) ipsr->dfh = 0;
+ if (imm.dfl) ipsr->dfl = 0;
+ if (imm.pp) { ipsr->pp = 0; psr.pp = 0; }
+ if (imm.up) { ipsr->up = 0; psr.up = 0; }
+ if (imm.sp) { ipsr->sp = 0; psr.sp = 0; }
+ if (imm.dt) vcpu_set_metaphysical_mode(vcpu,TRUE);
+ __asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory");
+ return IA64_NO_FAULT;
+}
+
+extern UINT64 vcpu_check_pending_interrupts(VCPU *vcpu);
+#define SPURIOUS_VECTOR 0xf
+
+IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24)
+{
+ struct ia64_psr psr, imm, *ipsr;
+ REGS *regs = vcpu_regs(vcpu);
+ UINT64 mask, enabling_interrupts = 0;
+
+ // TODO: All of these bits need to be virtualized
+ __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory");
+ imm = *(struct ia64_psr *)&imm24;
+ ipsr = (struct ia64_psr *)®s->cr_ipsr;
+ // just handle psr.sp,pp and psr.i,ic (and user mask) for now
+ mask = IA64_PSR_PP|IA64_PSR_SP|IA64_PSR_I|IA64_PSR_IC|IA64_PSR_UM |
+ IA64_PSR_DT|IA64_PSR_DFL|IA64_PSR_DFH;
+ if (imm24 & ~mask) return (IA64_ILLOP_FAULT);
+ if (imm.dfh) ipsr->dfh = 1;
+ if (imm.dfl) ipsr->dfl = 1;
+ if (imm.pp) { ipsr->pp = 1; psr.pp = 1; }
+ if (imm.sp) { ipsr->sp = 1; psr.sp = 1; }
+ if (imm.i) {
+ if (!PSCB(vcpu).interrupt_delivery_enabled) {
+//printf("vcpu_set_psr_sm: psr.ic 0->1 ");
+ enabling_interrupts = 1;
+ }
+ PSCB(vcpu).interrupt_delivery_enabled = 1;
+ }
+ if (imm.ic) PSCB(vcpu).interrupt_collection_enabled = 1;
+ // TODO: do this faster
+ if (imm.mfl) { ipsr->mfl = 1; psr.mfl = 1; }
+ if (imm.ac) { ipsr->ac = 1; psr.ac = 1; }
+ if (imm.up) { ipsr->up = 1; psr.up = 1; }
+ if (imm.be) {
+ printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
+ return (IA64_ILLOP_FAULT);
+ }
+ if (imm.dt) vcpu_set_metaphysical_mode(vcpu,FALSE);
+ __asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory");
+#if 0 // now done with deliver_pending_interrupts
+ if (enabling_interrupts) {
+ if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) {
+//printf("with interrupts pending\n");
+ return IA64_EXTINT_VECTOR;
+ }
+//else printf("but nothing pending\n");
+ }
+#endif
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_psr_l(VCPU *vcpu, UINT64 val)
+{
+ struct ia64_psr psr, newpsr, *ipsr;
+ REGS *regs = vcpu_regs(vcpu);
+ UINT64 enabling_interrupts = 0;
+
+ // TODO: All of these bits need to be virtualized
+ __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory");
+ newpsr = *(struct ia64_psr *)&val;
+ ipsr = (struct ia64_psr *)®s->cr_ipsr;
+ // just handle psr.up and psr.pp for now
+ //if (val & ~(IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP)) return (IA64_ILLOP_FAULT);
+ // however trying to set other bits can't be an error as it is in ssm
+ if (newpsr.dfh) ipsr->dfh = 1;
+ if (newpsr.dfl) ipsr->dfl = 1;
+ if (newpsr.pp) { ipsr->pp = 1; psr.pp = 1; }
+ if (newpsr.up) { ipsr->up = 1; psr.up = 1; }
+ if (newpsr.sp) { ipsr->sp = 1; psr.sp = 1; }
+ if (newpsr.i) {
+ if (!PSCB(vcpu).interrupt_delivery_enabled)
+ enabling_interrupts = 1;
+ PSCB(vcpu).interrupt_delivery_enabled = 1;
+ }
+ if (newpsr.ic) PSCB(vcpu).interrupt_collection_enabled = 1;
+ if (newpsr.mfl) { ipsr->mfl = 1; psr.mfl = 1; }
+ if (newpsr.ac) { ipsr->ac = 1; psr.ac = 1; }
+ if (newpsr.up) { ipsr->up = 1; psr.up = 1; }
+ if (newpsr.dt && newpsr.rt) vcpu_set_metaphysical_mode(vcpu,FALSE);
+ else vcpu_set_metaphysical_mode(vcpu,TRUE);
+ if (newpsr.be) {
+ printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
+ return (IA64_ILLOP_FAULT);
+ }
+ //__asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory");
+#if 0 // now done with deliver_pending_interrupts
+ if (enabling_interrupts) {
+ if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR)
+ return IA64_EXTINT_VECTOR;
+ }
+#endif
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_get_psr(VCPU *vcpu, UINT64 *pval)
+{
+ UINT64 psr;
+ struct ia64_psr newpsr;
+
+ // TODO: This needs to return a "filtered" view of
+ // the psr, not the actual psr. Probably the psr needs
+ // to be a field in regs (in addition to ipsr).
+ __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory");
+ newpsr = *(struct ia64_psr *)&psr;
+ if (newpsr.cpl == 2) newpsr.cpl = 0;
+ if (PSCB(vcpu).interrupt_delivery_enabled) newpsr.i = 1;
+ else newpsr.i = 0;
+ if (PSCB(vcpu).interrupt_collection_enabled) newpsr.ic = 1;
+ else newpsr.ic = 0;
+ *pval = *(unsigned long *)&newpsr;
+ return IA64_NO_FAULT;
+}
+
+BOOLEAN vcpu_get_psr_ic(VCPU *vcpu)
+{
+ return !!PSCB(vcpu).interrupt_collection_enabled;
+}
+
+BOOLEAN vcpu_get_psr_i(VCPU *vcpu)
+{
+ return !!PSCB(vcpu).interrupt_delivery_enabled;
+}
+
+UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr)
+{
+ UINT64 dcr = PSCB(vcpu).dcr;
+ PSR psr = {0};
+
+ //printf("*** vcpu_get_ipsr_int_state (0x%016lx)...",prevpsr);
+ psr.i64 = prevpsr;
+ psr.be = 0; if (dcr & IA64_DCR_BE) psr.be = 1;
+ psr.pp = 0; if (dcr & IA64_DCR_PP) psr.pp = 1;
+ psr.ic = PSCB(vcpu).interrupt_collection_enabled;
+ psr.i = PSCB(vcpu).interrupt_delivery_enabled;
+ psr.bn = PSCB(vcpu).banknum;
+ psr.dt = 1; psr.it = 1; psr.rt = 1;
+ if (psr.cpl == 2) psr.cpl = 0; // !!!! fool domain
+ // psr.pk = 1;
+ //printf("returns 0x%016lx...",psr.i64);
+ return psr.i64;
+}
+
+/**************************************************************************
+ VCPU control register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_get_dcr(VCPU *vcpu, UINT64 *pval)
+{
+extern unsigned long privop_trace;
+//privop_trace=0;
+//verbose("vcpu_get_dcr: called @%p\n",PSCB(vcpu).iip);
+ // Reads of cr.dcr on Xen always have the sign bit set, so
+ // a domain can differentiate whether it is running on SP or not
+ *pval = PSCB(vcpu).dcr | 0x8000000000000000L;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_iva(VCPU *vcpu, UINT64 *pval)
+{
+ *pval = PSCB(vcpu).iva & ~0x7fffL;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_pta(VCPU *vcpu, UINT64 *pval)
+{
+ *pval = PSCB(vcpu).pta;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_ipsr(VCPU *vcpu, UINT64 *pval)
+{
+ //REGS *regs = vcpu_regs(vcpu);
+ //*pval = regs->cr_ipsr;
+ *pval = PSCB(vcpu).ipsr;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_isr(VCPU *vcpu, UINT64 *pval)
+{
+ *pval = PSCB(vcpu).isr;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_iip(VCPU *vcpu, UINT64 *pval)
+{
+ //REGS *regs = vcpu_regs(vcpu);
+ //*pval = regs->cr_iip;
+ *pval = PSCB(vcpu).iip;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_ifa(VCPU *vcpu, UINT64 *pval)
+{
+ UINT64 val = PSCB(vcpu).ifa;
+ *pval = val;
+ return (IA64_NO_FAULT);
+}
+
+
+unsigned long vcpu_get_itir_on_fault(VCPU *vcpu, UINT64 ifa)
+{
+ ia64_rr rr;
+
+ rr.rrval = 0;
+ rr.ps = vcpu_get_rr_ps(vcpu,ifa);
+ rr.rid = vcpu_get_rr_rid(vcpu,ifa);
+ return (rr.rrval);
+}
+
+
+IA64FAULT vcpu_get_itir(VCPU *vcpu, UINT64 *pval)
+{
+ UINT64 val = PSCB(vcpu).itir;
+ *pval = val;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_iipa(VCPU *vcpu, UINT64 *pval)
+{
+ UINT64 val = PSCB(vcpu).iipa;
+ // SP entry code does not save iipa yet nor does it get
+ // properly delivered in the pscb
+ printf("*** vcpu_get_iipa: cr.iipa not fully implemented yet!!\n");
+ *pval = val;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_ifs(VCPU *vcpu, UINT64 *pval)
+{
+ //PSCB(vcpu).ifs = PSCB(vcpu)->regs.cr_ifs;
+ //*pval = PSCB(vcpu).regs.cr_ifs;
+ *pval = PSCB(vcpu).ifs;
+ PSCB(vcpu).incomplete_regframe = 0;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_iim(VCPU *vcpu, UINT64 *pval)
+{
+ UINT64 val = PSCB(vcpu).iim;
+ *pval = val;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_iha(VCPU *vcpu, UINT64 *pval)
+{
+ return vcpu_thash(vcpu,PSCB(vcpu).ifa,pval);
+}
+
+IA64FAULT vcpu_set_dcr(VCPU *vcpu, UINT64 val)
+{
+extern unsigned long privop_trace;
+//privop_trace=1;
+ // Reads of cr.dcr on SP always have the sign bit set, so
+ // a domain can differentiate whether it is running on SP or not
+ // Thus, writes of DCR should ignore the sign bit
+//verbose("vcpu_set_dcr: called\n");
+ PSCB(vcpu).dcr = val & ~0x8000000000000000L;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_iva(VCPU *vcpu, UINT64 val)
+{
+ PSCB(vcpu).iva = val & ~0x7fffL;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_pta(VCPU *vcpu, UINT64 val)
+{
+ if (val & IA64_PTA_LFMT) {
+ printf("*** No support for VHPT long format yet!!\n");
+ return (IA64_ILLOP_FAULT);
+ }
+ if (val & (0x3f<<9)) /* reserved fields */ return IA64_RSVDREG_FAULT;
+ if (val & 2) /* reserved fields */ return IA64_RSVDREG_FAULT;
+ PSCB(vcpu).pta = val;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_ipsr(VCPU *vcpu, UINT64 val)
+{
+ PSCB(vcpu).ipsr = val;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_isr(VCPU *vcpu, UINT64 val)
+{
+ PSCB(vcpu).isr = val;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_iip(VCPU *vcpu, UINT64 val)
+{
+ PSCB(vcpu).iip = val;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_increment_iip(VCPU *vcpu)
+{
+ REGS *regs = vcpu_regs(vcpu);
+ struct ia64_psr *ipsr = (struct ia64_psr *)®s->cr_ipsr;
+ if (ipsr->ri == 2) { ipsr->ri=0; regs->cr_iip += 16; }
+ else ipsr->ri++;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_ifa(VCPU *vcpu, UINT64 val)
+{
+ PSCB(vcpu).ifa = val;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_itir(VCPU *vcpu, UINT64 val)
+{
+ PSCB(vcpu).itir = val;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_iipa(VCPU *vcpu, UINT64 val)
+{
+ // SP entry code does not save iipa yet nor does it get
+ // properly delivered in the pscb
+ printf("*** vcpu_set_iipa: cr.iipa not fully implemented yet!!\n");
+ PSCB(vcpu).iipa = val;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_ifs(VCPU *vcpu, UINT64 val)
+{
+ //REGS *regs = vcpu_regs(vcpu);
+ PSCB(vcpu).ifs = val;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_iim(VCPU *vcpu, UINT64 val)
+{
+ PSCB(vcpu).iim = val;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_iha(VCPU *vcpu, UINT64 val)
+{
+ PSCB(vcpu).iha = val;
+ return IA64_NO_FAULT;
+}
+
+/**************************************************************************
+ VCPU interrupt control register access routines
+**************************************************************************/
+
+void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector)
+{
+ if (vector & ~0xff) {
+ printf("vcpu_pend_interrupt: bad vector\n");
+ return;
+ }
+ if (!test_bit(vector,PSCB(vcpu).delivery_mask)) return;
+ if (test_bit(vector,PSCB(vcpu).irr)) {
+//printf("vcpu_pend_interrupt: overrun\n");
+ }
+ set_bit(vector,PSCB(vcpu).irr);
+}
+
+#define IA64_TPR_MMI 0x10000
+#define IA64_TPR_MIC 0x000f0
+
+/* checks to see if a VCPU has any unmasked pending interrupts
+ * if so, returns the highest, else returns SPURIOUS_VECTOR */
+/* NOTE: Since this gets called from vcpu_get_ivr() and the
+ * semantics of "mov rx=cr.ivr" ignore the setting of the psr.i bit,
+ * this routine also ignores pscb.interrupt_delivery_enabled
+ * and this must be checked independently; see vcpu_deliverable interrupts() */
+UINT64 vcpu_check_pending_interrupts(VCPU *vcpu)
+{
+ UINT64 *p, *q, *r, bits, bitnum, mask, i, vector;
+
+ p = &PSCB(vcpu).irr[3];
+ q = &PSCB(vcpu).delivery_mask[3];
+ r = &PSCB(vcpu).insvc[3];
+ for (i = 3; ; p--, q--, r--, i--) {
+ bits = *p & *q;
+ if (bits) break; // got a potential interrupt
+ if (*r) {
+ // nothing in this word which is pending+inservice
+ // but there is one inservice which masks lower
+ return SPURIOUS_VECTOR;
+ }
+ if (i == 0) {
+ // checked all bits... nothing pending+inservice
+ return SPURIOUS_VECTOR;
+ }
+ }
+ // have a pending,deliverable interrupt... see if it is masked
+ bitnum = ia64_fls(bits);
+//printf("XXXXXXX vcpu_check_pending_interrupts: got bitnum=%p...",bitnum);
+ vector = bitnum+(i*64);
+ mask = 1L << bitnum;
+//printf("XXXXXXX vcpu_check_pending_interrupts: got vector=%p...",vector);
+ if (*r >= mask) {
+ // masked by equal inservice
+//printf("but masked by equal inservice\n");
+ return SPURIOUS_VECTOR;
+ }
+ if (PSCB(vcpu).tpr & IA64_TPR_MMI) {
+ // tpr.mmi is set
+//printf("but masked by tpr.mmi\n");
+ return SPURIOUS_VECTOR;
+ }
+ if (((PSCB(vcpu).tpr & IA64_TPR_MIC) + 15) >= vector) {
+ //tpr.mic masks class
+//printf("but masked by tpr.mic\n");
+ return SPURIOUS_VECTOR;
+ }
+
+//printf("returned to caller\n");
+ return vector;
+}
+
+UINT64 vcpu_deliverable_interrupts(VCPU *vcpu)
+{
+ return (vcpu_get_psr_i(vcpu) &&
+ vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR);
+}
+
+IA64FAULT vcpu_get_lid(VCPU *vcpu, UINT64 *pval)
+{
+extern unsigned long privop_trace;
+//privop_trace=1;
+ //TODO: Implement this
+ printf("vcpu_get_lid: WARNING: Getting cr.lid always returns zero\n");
+ *pval = 0;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval)
+{
+ int i;
+ UINT64 vector, mask;
+#if 1
+ static char firstivr = 1;
+ static char firsttime[256];
+ if (firstivr) {
+ int i;
+ for (i=0;i<256;i++) firsttime[i]=1;
+ firstivr=0;
+ }
+#endif
+
+ vector = vcpu_check_pending_interrupts(vcpu);
+ if (vector == SPURIOUS_VECTOR) {
+ PSCB(vcpu).pending_interruption = 0;
+ *pval = vector;
+ return IA64_NO_FAULT;
+ }
+ // now have an unmasked, pending, deliverable vector!
+ // getting ivr has "side effects"
+#if 0
+ if (firsttime[vector]) {
+ printf("*** First get_ivr on vector=%d,itc=%lx\n",
+ vector,ia64_get_itc());
+ firsttime[vector]=0;
+ }
+#endif
+ i = vector >> 6;
+ mask = 1L << (vector & 0x3f);
+//printf("ZZZZZZ vcpu_get_ivr: setting insvc mask for vector %ld\n",vector);
+ PSCB(vcpu).insvc[i] |= mask;
+ PSCB(vcpu).irr[i] &= ~mask;
+ PSCB(vcpu).pending_interruption--;
+ *pval = vector;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_get_tpr(VCPU *vcpu, UINT64 *pval)
+{
+ *pval = PSCB(vcpu).tpr;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_eoi(VCPU *vcpu, UINT64 *pval)
+{
+ *pval = 0L; // reads of eoi always return 0
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_irr0(VCPU *vcpu, UINT64 *pval)
+{
+#ifndef IRR_USE_FIXED
+ printk("vcpu_get_irr: called, not implemented yet\n");
+ return IA64_ILLOP_FAULT;
+#else
+ *pval = vcpu->irr[0];
+ return (IA64_NO_FAULT);
+#endif
+}
+
+IA64FAULT vcpu_get_irr1(VCPU *vcpu, UINT64 *pval)
+{
+#ifndef IRR_USE_FIXED
+ printk("vcpu_get_irr: called, not implemented yet\n");
+ return IA64_ILLOP_FAULT;
+#else
+ *pval = vcpu->irr[1];
+ return (IA64_NO_FAULT);
+#endif
+}
+
+IA64FAULT vcpu_get_irr2(VCPU *vcpu, UINT64 *pval)
+{
+#ifndef IRR_USE_FIXED
+ printk("vcpu_get_irr: called, not implemented yet\n");
+ return IA64_ILLOP_FAULT;
+#else
+ *pval = vcpu->irr[2];
+ return (IA64_NO_FAULT);
+#endif
+}
+
+IA64FAULT vcpu_get_irr3(VCPU *vcpu, UINT64 *pval)
+{
+#ifndef IRR_USE_FIXED
+ printk("vcpu_get_irr: called, not implemented yet\n");
+ return IA64_ILLOP_FAULT;
+#else
+ *pval = vcpu->irr[3];
+ return (IA64_NO_FAULT);
+#endif
+}
+
+IA64FAULT vcpu_get_itv(VCPU *vcpu, UINT64 *pval)
+{
+ *pval = PSCB(vcpu).itv;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_pmv(VCPU *vcpu, UINT64 *pval)
+{
+ *pval = PSCB(vcpu).pmv;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_cmcv(VCPU *vcpu, UINT64 *pval)
+{
+ *pval = PSCB(vcpu).cmcv;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_lrr0(VCPU *vcpu, UINT64 *pval)
+{
+ // fix this when setting values other than m-bit is supported
+ printf("vcpu_get_lrr0: Unmasked interrupts unsupported\n");
+ *pval = (1L << 16);
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_lrr1(VCPU *vcpu, UINT64 *pval)
+{
+ // fix this when setting values other than m-bit is supported
+ printf("vcpu_get_lrr1: Unmasked interrupts unsupported\n");
+ *pval = (1L << 16);
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_lid(VCPU *vcpu, UINT64 val)
+{
+ printf("vcpu_set_lid: Setting cr.lid is unsupported\n");
+ return (IA64_ILLOP_FAULT);
+}
+
+IA64FAULT vcpu_set_tpr(VCPU *vcpu, UINT64 val)
+{
+ if (val & 0xff00) return IA64_RSVDREG_FAULT;
+ PSCB(vcpu).tpr = val;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_eoi(VCPU *vcpu, UINT64 val)
+{
+ UINT64 *p, bits, vec, bitnum;
+ int i;
+
+ p = &PSCB(vcpu).insvc[3];
+ for (i = 3; (i >= 0) && !(bits = *p); i--, p--);
+ if (i < 0) {
+ printf("Trying to EOI interrupt when none are in-service.\r\n");
+ return;
+ }
+ bitnum = ia64_fls(bits);
+ vec = bitnum + (i*64);
+ /* clear the correct bit */
+ bits &= ~(1L << bitnum);
+ *p = bits;
+ /* clearing an eoi bit may unmask another pending interrupt... */
+ if (PSCB(vcpu).interrupt_delivery_enabled) { // but only if enabled...
+ // worry about this later... Linux only calls eoi
+ // with interrupts disabled
+ printf("Trying to EOI interrupt with interrupts enabled\r\n");
+ }
+//printf("YYYYY vcpu_set_eoi: Successful\n");
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_lrr0(VCPU *vcpu, UINT64 val)
+{
+ if (!(val & (1L << 16))) {
+ printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n");
+ return (IA64_ILLOP_FAULT);
+ }
+ // no place to save this state but nothing to do anyway
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_lrr1(VCPU *vcpu, UINT64 val)
+{
+ if (!(val & (1L << 16))) {
+ printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n");
+ return (IA64_ILLOP_FAULT);
+ }
+ // no place to save this state but nothing to do anyway
+ return (IA64_NO_FAULT);
+}
+
+
+IA64FAULT vcpu_set_itv(VCPU *vcpu, UINT64 val)
+{
+extern unsigned long privop_trace;
+//privop_trace=1;
+ if (val & 0xef00) return (IA64_ILLOP_FAULT);
+ PSCB(vcpu).itv = val;
+ if (val & 0x10000) {
+printf("**** vcpu_set_itv(%d): vitm=%lx, setting to 0\n",val,PSCB(vcpu).domain_itm);
+ PSCB(vcpu).domain_itm = 0;
+ }
+ else vcpu_enable_timer(vcpu,1000000L);
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_pmv(VCPU *vcpu, UINT64 val)
+{
+ if (val & 0xef00) /* reserved fields */ return IA64_RSVDREG_FAULT;
+ PSCB(vcpu).pmv = val;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_cmcv(VCPU *vcpu, UINT64 val)
+{
+ if (val & 0xef00) /* reserved fields */ return IA64_RSVDREG_FAULT;
+ PSCB(vcpu).cmcv = val;
+ return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+Interval timer routines
+**************************************************************************/
+
+BOOLEAN vcpu_timer_disabled(VCPU *vcpu)
+{
+ UINT64 itv = PSCB(vcpu).itv;
+ return(!itv || !!(itv & 0x10000));
+}
+
+BOOLEAN vcpu_timer_expired(VCPU *vcpu)
+{
+ unsigned long domain_itm = PSCB(vcpu).domain_itm;
+ unsigned long now = ia64_get_itc();
+
+ if (domain_itm && (now > domain_itm) &&
+ !vcpu_timer_disabled(vcpu)) return TRUE;
+ return FALSE;
+}
+
+void vcpu_safe_set_itm(unsigned long val)
+{
+ unsigned long epsilon = 100;
+ UINT64 now = ia64_get_itc();
+
+ local_irq_disable();
+ while (1) {
+//printf("*** vcpu_safe_set_itm: Setting itm to %lx, itc=%lx\n",val,now);
+ ia64_set_itm(val);
+ if (val > (now = ia64_get_itc())) break;
+ val = now + epsilon;
+ epsilon <<= 1;
+ }
+ local_irq_enable();
+}
+
+void vcpu_set_next_timer(VCPU *vcpu)
+{
+ UINT64 d = PSCB(vcpu).domain_itm;
+ //UINT64 s = PSCB(vcpu).xen_itm;
+ UINT64 s = local_cpu_data->itm_next;
+ UINT64 now = ia64_get_itc();
+ //UINT64 interval = PSCB(vcpu).xen_timer_interval;
+
+ /* gloss over the wraparound problem for now... we know it exists
+ * but it doesn't matter right now */
+
+#if 0
+ /* ensure at least next SP tick is in the future */
+ if (!interval) PSCB(vcpu).xen_itm = now +
+#if 0
+ (running_on_sim() ? SIM_DEFAULT_CLOCK_RATE :
+ DEFAULT_CLOCK_RATE);
+#else
+ 3000000;
+//printf("vcpu_set_next_timer: HACK!\n");
+#endif
+#if 0
+ if (PSCB(vcpu).xen_itm < now)
+ while (PSCB(vcpu).xen_itm < now + (interval>>1))
+ PSCB(vcpu).xen_itm += interval;
+#endif
+#endif
+
+ if (is_idle_task(vcpu)) {
+ printf("****** vcpu_set_next_timer called during idle!!\n");
+ }
+ //s = PSCB(vcpu).xen_itm;
+ if (d && (d > now) && (d < s)) {
+ vcpu_safe_set_itm(d);
+ //using_domain_as_itm++;
+ }
+ else {
+ vcpu_safe_set_itm(s);
+ //using_xen_as_itm++;
+ }
+}
+
+// parameter is a time interval specified in cycles
+void vcpu_enable_timer(VCPU *vcpu,UINT64 cycles)
+{
+ PSCB(vcpu).xen_timer_interval = cycles;
+ vcpu_set_next_timer(vcpu);
+ printf("vcpu_enable_timer(%d): interval set to %d cycles\n",
+ PSCB(vcpu).xen_timer_interval);
+ __set_bit(PSCB(vcpu).itv, PSCB(vcpu).delivery_mask);
+}
+
+IA64FAULT vcpu_set_itm(VCPU *vcpu, UINT64 val)
+{
+ UINT now = ia64_get_itc();
+
+ //if (val < now) val = now + 1000;
+//printf("*** vcpu_set_itm: called with %lx\n",val);
+ PSCB(vcpu).domain_itm = val;
+ vcpu_set_next_timer(vcpu);
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_itc(VCPU *vcpu, UINT64 val)
+{
+
+ UINT64 oldnow = ia64_get_itc();
+ UINT64 olditm = PSCB(vcpu).domain_itm;
+ unsigned long d = olditm - oldnow;
+ unsigned long x = local_cpu_data->itm_next - oldnow;
+
+ UINT64 newnow = val, min_delta;
+
+ local_irq_disable();
+ if (olditm) {
+printf("**** vcpu_set_itc(%lx): vitm changed to %lx\n",val,newnow+d);
+ PSCB(vcpu).domain_itm = newnow + d;
+ }
+ local_cpu_data->itm_next = newnow + x;
+ d = PSCB(vcpu).domain_itm;
+ x = local_cpu_data->itm_next;
+
+ ia64_set_itc(newnow);
+ if (d && (d > newnow) && (d < x)) {
+ vcpu_safe_set_itm(d);
+ //using_domain_as_itm++;
+ }
+ else {
+ vcpu_safe_set_itm(x);
+ //using_xen_as_itm++;
+ }
+ local_irq_enable();
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_itm(VCPU *vcpu, UINT64 *pval)
+{
+ //FIXME: Implement this
+ printf("vcpu_get_itm: Getting cr.itm is unsupported... continuing\n");
+ return (IA64_NO_FAULT);
+ //return (IA64_ILLOP_FAULT);
+}
+
+IA64FAULT vcpu_get_itc(VCPU *vcpu, UINT64 *pval)
+{
+ //TODO: Implement this
+ printf("vcpu_get_itc: Getting ar.itc is unsupported\n");
+ return (IA64_ILLOP_FAULT);
+}
+
+void vcpu_pend_timer(VCPU *vcpu)
+{
+ UINT64 itv = PSCB(vcpu).itv & 0xff;
+
+ if (vcpu_timer_disabled(vcpu)) return;
+ vcpu_pend_interrupt(vcpu, itv);
+}
+
+//FIXME: This is a hack because everything dies if a timer tick is lost
+void vcpu_poke_timer(VCPU *vcpu)
+{
+ UINT64 itv = PSCB(vcpu).itv & 0xff;
+ UINT64 now = ia64_get_itc();
+ UINT64 itm = PSCB(vcpu).domain_itm;
+ UINT64 irr;
+
+ if (vcpu_timer_disabled(vcpu)) return;
+ if (!itm) return;
+ if (itv != 0xefL) {
+ printf("vcpu_poke_timer: unimplemented itv=%lx!\n",itv);
+ while(1);
+ }
+ // using 0xef instead of itv so can get real irr
+ if (now > itm && !test_bit(0xefL, PSCB(vcpu).insvc)) {
+ if (!test_bit(0xefL,PSCB(vcpu).irr)) {
+ irr = ia64_getreg(_IA64_REG_CR_IRR3);
+ if (irr & (1L<<(0xef-0xc0))) return;
+if (now-itm>0x800000)
+printf("*** poking timer: now=%lx,vitm=%lx,xitm=%lx,itm=%lx\n",now,itm,local_cpu_data->itm_next,ia64_get_itm());
+ vcpu_pend_interrupt(vcpu, 0xefL);
+ }
+ }
+}
+
+
+/**************************************************************************
+Privileged operation emulation routines
+**************************************************************************/
+
+IA64FAULT vcpu_force_data_miss(VCPU *vcpu, UINT64 ifa)
+{
+ PSCB(vcpu).ifa = ifa; // privop traps don't set ifa so do it here
+ return (IA64_DATA_TLB_VECTOR | IA64_FORCED_IFA);
+}
+
+
+IA64FAULT vcpu_rfi(VCPU *vcpu)
+{
+ // TODO: Only allowed for current vcpu
+ PSR psr;
+ UINT64 int_enable, regspsr = 0;
+ UINT64 ifs;
+ REGS *regs = vcpu_regs(vcpu);
+ extern void dorfirfi(void);
+
+ psr.i64 = PSCB(vcpu).ipsr;
+ if (psr.cpl < 3) psr.cpl = 2;
+ if (psr.i) PSCB(vcpu).interrupt_delivery_enabled = 1;
+ int_enable = psr.i;
+ if (psr.ic) PSCB(vcpu).interrupt_collection_enabled = 1;
+ if (psr.dt && psr.rt && psr.it) vcpu_set_metaphysical_mode(vcpu,FALSE);
+ else vcpu_set_metaphysical_mode(vcpu,TRUE);
+ psr.ic = 1; psr.i = 1;
+ psr.dt = 1; psr.rt = 1; psr.it = 1;
+ psr.bn = 1;
+ //psr.pk = 1; // checking pkeys shouldn't be a problem but seems broken
+ if (psr.be) {
+ printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
+ return (IA64_ILLOP_FAULT);
+ }
+ PSCB(vcpu).incomplete_regframe = 0; // is this necessary?
+ ifs = PSCB(vcpu).ifs;
+ //if ((ifs & regs->cr_ifs & 0x8000000000000000L) && ifs != regs->cr_ifs) {
+ //if ((ifs & 0x8000000000000000L) && ifs != regs->cr_ifs) {
+ if (ifs & regs->cr_ifs & 0x8000000000000000L) {
+#define SI_OFS(x) ((char *)(&PSCB(vcpu).x) - (char *)(vcpu->shared_info))
+if (SI_OFS(iip)!=0x150 || SI_OFS(ipsr)!=0x148 || SI_OFS(ifs)!=0x158) {
+printf("SI_CR_IIP/IPSR/IFS_OFFSET CHANGED, SEE dorfirfi\n");
+while(1);
+}
+ // TODO: validate PSCB(vcpu).iip
+ // TODO: PSCB(vcpu).ipsr = psr;
+ PSCB(vcpu).ipsr = psr.i64;
+ // now set up the trampoline
+ regs->cr_iip = *(unsigned long *)dorfirfi; // function pointer!!
+ __asm__ __volatile ("mov %0=psr;;":"=r"(regspsr)::"memory");
+ regs->cr_ipsr = regspsr & ~(IA64_PSR_I | IA64_PSR_IC | IA64_PSR_BN);
+ }
+ else {
+ regs->cr_ipsr = psr.i64;
+ regs->cr_iip = PSCB(vcpu).iip;
+ }
+ PSCB(vcpu).interrupt_collection_enabled = 1;
+ vcpu_bsw1(vcpu);
+ PSCB(vcpu).interrupt_delivery_enabled = int_enable;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_cover(VCPU *vcpu)
+{
+ REGS *regs = vcpu_regs(vcpu);
+
+ if (!PSCB(vcpu).interrupt_collection_enabled) {
+ if (!PSCB(vcpu).incomplete_regframe)
+ PSCB(vcpu).ifs = regs->cr_ifs;
+ else PSCB(vcpu).incomplete_regframe = 0;
+ }
+ regs->cr_ifs = 0;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval)
+{
+ extern unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr);
+ UINT64 pta = PSCB(vcpu).pta;
+ UINT64 pta_sz = (pta & IA64_PTA_SZ(0x3f)) >> IA64_PTA_SZ_BIT;
+ UINT64 pta_base = pta & ~((1UL << IA64_PTA_BASE_BIT)-1);
+ UINT64 Mask = (1L << pta_sz) - 1;
+ UINT64 Mask_60_15 = (Mask >> 15) & 0x3fffffffffff;
+ UINT64 compMask_60_15 = ~Mask_60_15;
+ //UINT64 rr_ps = RR_TO_PS(get_rr(vadr));
+ UINT64 rr_ps = vcpu_get_rr_ps(vcpu,vadr);
+ UINT64 VHPT_offset = (vadr >> rr_ps) << 3;
+ UINT64 VHPT_addr1 = vadr & 0xe000000000000000L;
+ UINT64 VHPT_addr2a =
+ ((pta_base >> 15) & 0x3fffffffffff) & compMask_60_15;
+ UINT64 VHPT_addr2b =
+ ((VHPT_offset >> 15) & 0x3fffffffffff) & Mask_60_15;;
+ UINT64 VHPT_addr3 = VHPT_offset & 0x3fff;
+ UINT64 VHPT_addr = VHPT_addr1 | ((VHPT_addr2a | VHPT_addr2b) << 15) |
+ VHPT_addr3;
+
+ if (VHPT_addr1 == 0xe000000000000000L) {
+ printf("vcpu_thash: thash unsupported with rr7 @%lx\n",
+ PSCB(vcpu).iip);
+ return (IA64_ILLOP_FAULT);
+ }
+//verbose("vcpu_thash: vadr=%p, VHPT_addr=%p\n",vadr,VHPT_addr);
+ *pval = VHPT_addr;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *padr)
+{
+ printf("vcpu_ttag: ttag instruction unsupported\n");
+ return (IA64_ILLOP_FAULT);
+}
+
+IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr)
+{
+ extern TR_ENTRY *match_tr(VCPU *,UINT64);
+ extern TR_ENTRY *match_dtlb(VCPU *,UINT64);
+ TR_ENTRY *trp;
+ UINT64 mask;
+
+extern unsigned long privop_trace;
+ if ((trp=match_tr(current,vadr)) || (trp=match_dtlb(current,vadr))) {
+ mask = (1L << trp->ps) - 1;
+ *padr = ((trp->ppn << 12) & ~mask) | (vadr & mask);
+ verbose("vcpu_tpa: addr=%p @%p, successful, padr=%p\n",vadr,PSCB(vcpu).iip,*padr);
+ return (IA64_NO_FAULT);
+ }
+ verbose("vcpu_tpa addr=%p, @%p, forcing data miss\n",vadr,PSCB(vcpu).iip);
+ return vcpu_force_data_miss(vcpu, vadr);
+}
+
+IA64FAULT vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key)
+{
+ printf("vcpu_tak: tak instruction unsupported\n");
+ return (IA64_ILLOP_FAULT);
+ // HACK ALERT: tak does a thash for now
+ //return vcpu_thash(vcpu,vadr,key);
+}
+
+/**************************************************************************
+ VCPU debug breakpoint register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_set_dbr(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+ // TODO: unimplemented DBRs return a reserved register fault
+ // TODO: Should set Logical CPU state, not just physical
+ ia64_set_dbr(reg,val);
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_ibr(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+ // TODO: unimplemented IBRs return a reserved register fault
+ // TODO: Should set Logical CPU state, not just physical
+ ia64_set_ibr(reg,val);
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_dbr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+ // TODO: unimplemented DBRs return a reserved register fault
+ UINT64 val = ia64_get_dbr(reg);
+ *pval = val;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_ibr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+ // TODO: unimplemented IBRs return a reserved register fault
+ UINT64 val = ia64_get_ibr(reg);
+ *pval = val;
+ return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+ VCPU performance monitor register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_set_pmc(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+ // TODO: Should set Logical CPU state, not just physical
+ // NOTE: Writes to unimplemented PMC registers are discarded
+ ia64_set_pmc(reg,val);
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_pmd(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+ // TODO: Should set Logical CPU state, not just physical
+ // NOTE: Writes to unimplemented PMD registers are discarded
+ ia64_set_pmd(reg,val);
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_pmc(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+ // NOTE: Reads from unimplemented PMC registers return zero
+ UINT64 val = (UINT64)ia64_get_pmc(reg);
+ *pval = val;
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_pmd(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+ // NOTE: Reads from unimplemented PMD registers return zero
+ UINT64 val = (UINT64)ia64_get_pmd(reg);
+ *pval = val;
+ return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+ VCPU banked general register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_bsw0(VCPU *vcpu)
+{
+ REGS *regs = vcpu_regs(vcpu);
+ unsigned long *r = ®s->r16;
+ unsigned long *b0 = &PSCB(vcpu).bank0_regs[0];
+ unsigned long *b1 = &PSCB(vcpu).bank1_regs[0];
+ int i;
+
+ if (PSCB(vcpu).banknum) {
+ for (i = 0; i < 16; i++) { *b1++ = *r; *r++ = *b0++; }
+ PSCB(vcpu).banknum = 0;
+ }
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_bsw1(VCPU *vcpu)
+{
+ REGS *regs = vcpu_regs(vcpu);
+ unsigned long *r = ®s->r16;
+ unsigned long *b0 = &PSCB(vcpu).bank0_regs[0];
+ unsigned long *b1 = &PSCB(vcpu).bank1_regs[0];
+ int i;
+
+ if (!PSCB(vcpu).banknum) {
+ for (i = 0; i < 16; i++) { *b0++ = *r; *r++ = *b1++; }
+ PSCB(vcpu).banknum = 1;
+ }
+ return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+ VCPU cpuid access routines
+**************************************************************************/
+
+
+IA64FAULT vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+ // FIXME: This could get called as a result of a rsvd-reg fault
+ // if reg > 3
+ switch(reg) {
+ case 0:
+ case 1:
+ memcpy(pval,"Xen/ia64",8);
+ break;
+ case 2:
+ *pval = 0;
+ break;
+ case 3:
+ *pval = 0; //FIXME: See vol1, 3.1.11
+ break;
+ case 4:
+ *pval = 1; //FIXME: See vol1, 3.1.11
+ break;
+ default:
+ *pval = 0; //FIXME: See vol1, 3.1.11
+ break;
+ }
+ return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+ VCPU region register access routines
+**************************************************************************/
+
+unsigned long vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr)
+{
+
+ ia64_rr rr;
+
+ rr.rrval = PSCB(vcpu).rrs[vadr>>61];
+ return(rr.ve);
+}
+
+
+unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr)
+{
+
+ ia64_rr rr;
+
+ rr.rrval = PSCB(vcpu).rrs[vadr>>61];
+ return(rr.ps);
+}
+
+
+unsigned long vcpu_get_rr_rid(VCPU *vcpu,UINT64 vadr)
+{
+
+ ia64_rr rr;
+
+ rr.rrval = PSCB(vcpu).rrs[vadr>>61];
+ return(rr.rid);
+}
+
+
+IA64FAULT vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+ extern void set_one_rr(UINT64, UINT64);
+ PSCB(vcpu).rrs[reg>>61] = val;
+ // warning: set_one_rr() does it "live"
+ set_one_rr(reg,val);
+ return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_rr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+ UINT val = PSCB(vcpu).rrs[reg>>61];
+ *pval = val;
+ return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+ VCPU protection key register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+#ifndef PKR_USE_FIXED
+ printk("vcpu_get_pkr: called, not implemented yet\n");
+ return IA64_ILLOP_FAULT;
+#else
+ UINT64 val = (UINT64)ia64_get_pkr(reg);
+ *pval = val;
+ return (IA64_NO_FAULT);
+#endif
+}
+
+IA64FAULT vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+#ifndef PKR_USE_FIXED
+ printk("vcpu_set_pkr: called, not implemented yet\n");
+ return IA64_ILLOP_FAULT;
+#else
+// if (reg >= NPKRS) return (IA64_ILLOP_FAULT);
+ vcpu->pkrs[reg] = val;
+ ia64_set_pkr(reg,val);
+ return (IA64_NO_FAULT);
+#endif
+}
+
+/**************************************************************************
+ VCPU translation register access routines
+**************************************************************************/
+
+static void vcpu_purge_tr_entry(TR_ENTRY *trp)
+{
+ trp->p = 0;
+}
+
+static void vcpu_set_tr_entry(TR_ENTRY *trp, UINT64 pte, UINT64 itir, UINT64 ifa)
+{
+ UINT64 ps;
+
+ trp->itir = itir;
+ trp->rid = virtualize_rid(current, get_rr(ifa) & RR_RID_MASK);
+ trp->p = 1;
+ ps = trp->ps;
+ trp->page_flags = pte;
+ if (trp->pl < 2) trp->pl = 2;
+ trp->vadr = ifa & ~0xfff;
+ if (ps > 12) { // "ignore" relevant low-order bits
+ trp->ppn &= ~((1UL<<(ps-12))-1);
+ trp->vadr &= ~((1UL<<ps)-1);
+ }
+}
+
+TR_ENTRY *vcpu_match_tr_entry(VCPU *vcpu, TR_ENTRY *trp, UINT64 ifa, int count)
+{
+ unsigned long rid = (get_rr(ifa) & RR_RID_MASK);
+ int i;
+
+ for (i = 0; i < count; i++, trp++) {
+ if (!trp->p) continue;
+ if (physicalize_rid(vcpu,trp->rid) != rid) continue;
+ if (ifa < trp->vadr) continue;
+ if (ifa >= (trp->vadr + (1L << trp->ps)) - 1) continue;
+ //if (trp->key && !match_pkr(vcpu,trp->key)) continue;
+ return trp;
+ }
+ return 0;
+}
+
+TR_ENTRY *match_tr(VCPU *vcpu, unsigned long ifa)
+{
+ TR_ENTRY *trp;
+
+ trp = vcpu_match_tr_entry(vcpu,vcpu->shared_info->arch.dtrs,ifa,NDTRS);
+ if (trp) return trp;
+ trp = vcpu_match_tr_entry(vcpu,vcpu->shared_info->arch.itrs,ifa,NITRS);
+ if (trp) return trp;
+ return 0;
+}
+
+IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte,
+ UINT64 itir, UINT64 ifa)
+{
+ TR_ENTRY *trp;
+
+ if (slot >= NDTRS) return IA64_RSVDREG_FAULT;
+ trp = &PSCB(vcpu).dtrs[slot];
+ vcpu_set_tr_entry(trp,pte,itir,ifa);
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte,
+ UINT64 itir, UINT64 ifa)
+{
+ TR_ENTRY *trp;
+
+ if (slot >= NITRS) return IA64_RSVDREG_FAULT;
+ trp = &PSCB(vcpu).itrs[slot];
+ vcpu_set_tr_entry(trp,pte,itir,ifa);
+ return IA64_NO_FAULT;
+}
+
+/**************************************************************************
+ VCPU translation cache access routines
+**************************************************************************/
+
+void foobar(void) { /*vcpu_verbose = 1;*/ }
+
+extern VCPU *dom0;
+
+void vcpu_itc_no_srlz(VCPU *vcpu, UINT64 IorD, UINT64 vaddr, UINT64 pte, UINT64 logps)
+{
+ unsigned long psr;
+ unsigned long ps = (vcpu==dom0) ? logps : PAGE_SHIFT;
+
+ // FIXME: validate ifa here (not in Xen space), COULD MACHINE CHECK!
+ // FIXME, must be inlined or potential for nested fault here!
+ psr = ia64_clear_ic();
+ ia64_itc(IorD,vaddr,pte,ps); // FIXME: look for bigger mappings
+ ia64_set_psr(psr);
+ // ia64_srlz_i(); // no srls req'd, will rfi later
+ if (IorD & 0x1) vcpu_set_tr_entry(&PSCB(vcpu).itlb,pte,logps<<2,vaddr);
+ if (IorD & 0x2) vcpu_set_tr_entry(&PSCB(vcpu).dtlb,pte,logps<<2,vaddr);
+}
+
+TR_ENTRY *match_dtlb(VCPU *vcpu, unsigned long ifa)
+{
+ return vcpu_match_tr_entry(vcpu,&vcpu->shared_info->arch.dtlb,ifa,1);
+}
+
+IA64FAULT vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa)
+{
+ unsigned long pteval, logps = (itir >> 2) & 0x3f;
+ unsigned long translate_domain_pte(UINT64,UINT64,UINT64);
+
+ if (((itir & ~0xfc) >> 2) < PAGE_SHIFT) {
+ printf("vcpu_itc_d: domain trying to use smaller page size!\n");
+ //FIXME: kill domain here
+ while(1);
+ }
+ //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize
+ pteval = translate_domain_pte(pte,ifa,itir);
+ if (!pteval) return IA64_ILLOP_FAULT;
+ vcpu_itc_no_srlz(vcpu,2,ifa,pteval,logps);
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa)
+{
+ unsigned long pteval, logps = (itir >> 2) & 0x3f;
+ unsigned long translate_domain_pte(UINT64,UINT64,UINT64);
+
+ // FIXME: validate ifa here (not in Xen space), COULD MACHINE CHECK!
+ if (((itir & ~0xfc) >> 2) < PAGE_SHIFT) {
+ printf("vcpu_itc_i: domain trying to use smaller page size!\n");
+ //FIXME: kill domain here
+ while(1);
+ }
+ //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize
+ pteval = translate_domain_pte(pte,ifa,itir);
+ // FIXME: what to do if bad physical address? (machine check?)
+ if (!pteval) return IA64_ILLOP_FAULT;
+ vcpu_itc_no_srlz(vcpu, 1,ifa,pteval,logps);
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 addr_range)
+{
+ printk("vcpu_ptc_l: called, not implemented yet\n");
+ return IA64_ILLOP_FAULT;
+}
+
+IA64FAULT vcpu_fc(VCPU *vcpu, UINT64 vadr)
+{
+ UINT64 mpaddr;
+ IA64FAULT fault;
+ unsigned long lookup_domain_mpa(VCPU *,unsigned long);
+ unsigned long pteval, dom_imva;
+
+ fault = vcpu_tpa(vcpu, vadr, &mpaddr);
+ if (fault == IA64_NO_FAULT) {
+ struct domain *dom0;
+ unsigned long dom0_start, dom0_size;
+ if (vcpu == dom0) {
+ if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
+ printk("vcpu_fc: bad dom0 mpaddr %p!\n",mpaddr);
+ }
+ }
+ pteval = lookup_domain_mpa(vcpu,mpaddr);
+ if (pteval) {
+ dom_imva = __va(pteval & _PFN_MASK);
+ ia64_fc(dom_imva);
+ }
+ else {
+ REGS *regs = vcpu_regs(vcpu);
+ printk("vcpu_fc: can't flush vadr=%p, iip=%p\n",
+ vadr,regs->cr_iip);
+ }
+ }
+ return fault;
+}
+
+IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr)
+{
+
+ // Note that this only needs to be called once, i.e. the
+ // architected loop to purge the entire TLB, should use
+ // base = stride1 = stride2 = 0, count0 = count 1 = 1
+
+ // FIXME: When VHPT is in place, flush that too!
+ local_flush_tlb_all();
+ // just invalidate the "whole" tlb
+ vcpu_purge_tr_entry(&PSCB(vcpu).dtlb);
+ vcpu_purge_tr_entry(&PSCB(vcpu).itlb);
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 addr_range)
+{
+ printk("vcpu_ptc_g: called, not implemented yet\n");
+ return IA64_ILLOP_FAULT;
+}
+
+IA64FAULT vcpu_ptc_ga(VCPU *vcpu,UINT64 vadr,UINT64 addr_range)
+{
+ extern ia64_global_tlb_purge(UINT64 start, UINT64 end, UINT64 nbits);
+ // FIXME: validate not flushing Xen addresses
+ // if (Xen address) return(IA64_ILLOP_FAULT);
+ // FIXME: ??breaks if domain PAGE_SIZE < Xen PAGE_SIZE
+ ia64_global_tlb_purge(vadr,vadr+addr_range,PAGE_SHIFT);
+ vcpu_purge_tr_entry(&PSCB(vcpu).dtlb);
+ vcpu_purge_tr_entry(&PSCB(vcpu).itlb);
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 addr_range)
+{
+ printf("vcpu_ptr_d: Purging TLB is unsupported\n");
+ return (IA64_ILLOP_FAULT);
+}
+
+IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 addr_range)
+{
+ printf("vcpu_ptr_i: Purging TLB is unsupported\n");
+ return (IA64_ILLOP_FAULT);
+}
+
+void vcpu_set_regs(VCPU *vcpu, REGS *regs)
+{
+ vcpu->regs = regs;
+}
--- /dev/null
+/*
+ * Assembly support routines for Xen/ia64
+ *
+ * Copyright (C) 2004 Hewlett-Packard Co
+ * Dan Magenheimer <dan.magenheimer@hp.com>
+ */
+
+#include <linux/config.h>
+#include <asm/asmmacro.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/vhpt.h>
+
+#define RunningOnHpSki(rx,ry,pn) \
+ addl rx = 2, r0; \
+ addl ry = 3, r0; \
+ ;; \
+ mov rx = cpuid[rx]; \
+ mov ry = cpuid[ry]; \
+ ;; \
+ cmp.eq pn,p0 = 0, rx; \
+ ;; \
+ (pn) movl rx = 0x7000004 ; \
+ ;; \
+ (pn) cmp.eq pn,p0 = ry, rx; \
+ ;;
+
+//int platform_is_hp_ski(void)
+GLOBAL_ENTRY(platform_is_hp_ski)
+ mov r8 = 0
+ RunningOnHpSki(r3,r9,p8)
+(p8) mov r8 = 1
+ br.ret.sptk.many b0
+END(platform_is_hp_ski)
+
+// Change rr7 to the passed value while ensuring
+// Xen is mapped into the new region
+#define PSR_BITS_TO_CLEAR \
+ (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT | \
+ IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \
+ IA64_PSR_DFL | IA64_PSR_DFH)
+// FIXME? Note that this turns off the DB bit (debug)
+#define PSR_BITS_TO_SET IA64_PSR_BN
+
+GLOBAL_ENTRY(ia64_new_rr7)
+ // not sure this unwind statement is correct...
+ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(1)
+ alloc loc1 = ar.pfs, 1, 7, 0, 0
+1: {
+ mov r28 = in0 // copy procedure index
+ mov r8 = ip // save ip to compute branch
+ mov loc0 = rp // save rp
+ };;
+ .body
+ movl loc2=PERCPU_ADDR
+ ;;
+ tpa loc2=loc2 // grab this BEFORE changing rr7
+ ;;
+#if VHPT_ENABLED
+ movl loc6=VHPT_ADDR
+ ;;
+ tpa loc6=loc6 // grab this BEFORE changing rr7
+ ;;
+#endif
+ movl loc5=SHAREDINFO_ADDR
+ ;;
+ tpa loc5=loc5 // grab this BEFORE changing rr7
+ ;;
+ mov loc3 = psr // save psr
+ adds r8 = 1f-1b,r8 // calculate return address for call
+ ;;
+ tpa r8=r8 // convert rp to physical
+ ;;
+ mov loc4=ar.rsc // save RSE configuration
+ ;;
+ mov ar.rsc=0 // put RSE in enforced lazy, LE mode
+ movl r16=PSR_BITS_TO_CLEAR
+ movl r17=PSR_BITS_TO_SET
+ ;;
+ or loc3=loc3,r17 // add in psr the bits to set
+ ;;
+ andcm r16=loc3,r16 // removes bits to clear from psr
+ br.call.sptk.many rp=ia64_switch_mode_phys
+1:
+ // now in physical mode with psr.i/ic off so do rr7 switch
+ dep r16=-1,r0,61,3
+ ;;
+ mov rr[r16]=in0
+ srlz.d
+ ;;
+
+ // re-pin mappings for kernel text and data
+ mov r18=KERNEL_TR_PAGE_SHIFT<<2
+ movl r17=KERNEL_START
+ ;;
+ rsm psr.i | psr.ic
+ ;;
+ srlz.i
+ ;;
+ ptr.i r17,r18
+ ptr.d r17,r18
+ ;;
+ mov cr.itir=r18
+ mov cr.ifa=r17
+ mov r16=IA64_TR_KERNEL
+ //mov r3=ip
+ movl r18=PAGE_KERNEL
+ ;;
+ dep r2=0,r3,0,KERNEL_TR_PAGE_SHIFT
+ ;;
+ or r18=r2,r18
+ ;;
+ srlz.i
+ ;;
+ itr.i itr[r16]=r18
+ ;;
+ itr.d dtr[r16]=r18
+ ;;
+
+ // re-pin mappings for stack (current), per-cpu, vhpt, and shared info
+
+ // unless overlaps with KERNEL_TR
+ dep r18=0,r13,0,KERNEL_TR_PAGE_SHIFT
+ ;;
+ cmp.eq p7,p0=r17,r18
+(p7) br.cond.sptk .stack_overlaps
+ ;;
+ movl r25=PAGE_KERNEL
+ dep r20=0,r13,50,14 // physical address of "current"
+ ;;
+ or r23=r25,r20 // construct PA | page properties
+ mov r25=IA64_GRANULE_SHIFT<<2
+ ;;
+ ptr.d r13,r25
+ ;;
+ mov cr.itir=r25
+ mov cr.ifa=r13 // VA of next task...
+ ;;
+ mov r25=IA64_TR_CURRENT_STACK
+ ;;
+ itr.d dtr[r25]=r23 // wire in new mapping...
+ ;;
+.stack_overlaps:
+
+ movl r22=PERCPU_ADDR
+ ;;
+ movl r25=PAGE_KERNEL
+ ;;
+ mov r20=loc2 // saved percpu physical address
+ ;;
+ or r23=r25,r20 // construct PA | page properties
+ mov r24=PERCPU_PAGE_SHIFT<<2
+ ;;
+ ptr.d r22,r24
+ ;;
+ mov cr.itir=r24
+ mov cr.ifa=r22
+ ;;
+ mov r25=IA64_TR_PERCPU_DATA
+ ;;
+ itr.d dtr[r25]=r23 // wire in new mapping...
+ ;;
+
+#if VHPT_ENABLED
+ movl r22=VHPT_ADDR
+ ;;
+ movl r25=PAGE_KERNEL
+ ;;
+ mov r20=loc6 // saved vhpt physical address
+ ;;
+ or r23=r25,r20 // construct PA | page properties
+ mov r24=VHPT_PAGE_SHIFT<<2
+ ;;
+ ptr.d r22,r24
+ ;;
+ mov cr.itir=r24
+ mov cr.ifa=r22
+ ;;
+ mov r25=IA64_TR_VHPT
+ ;;
+ itr.d dtr[r25]=r23 // wire in new mapping...
+ ;;
+#endif
+
+ movl r22=SHAREDINFO_ADDR
+ ;;
+ movl r25=PAGE_KERNEL
+ ;;
+ mov r20=loc5 // saved sharedinfo physical address
+ ;;
+ or r23=r25,r20 // construct PA | page properties
+ mov r24=PAGE_SHIFT<<2
+ ;;
+ ptr.d r22,r24
+ ;;
+ mov cr.itir=r24
+ mov cr.ifa=r22
+ ;;
+ mov r25=IA64_TR_SHARED_INFO
+ ;;
+ itr.d dtr[r25]=r23 // wire in new mapping...
+ ;;
+
+ // done, switch back to virtual and return
+ mov r16=loc3 // r16= original psr
+ br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
+ mov psr.l = loc3 // restore init PSR
+
+ mov ar.pfs = loc1
+ mov rp = loc0
+ ;;
+ mov ar.rsc=loc4 // restore RSE configuration
+ srlz.d // seralize restoration of psr.l
+ br.ret.sptk.many rp
+END(ia64_new_rr7)
+
+#include "minstate.h"
+
+GLOBAL_ENTRY(ia64_prepare_handle_privop)
+ .prologue
+ /*
+ * r16 = fake ar.pfs, we simply need to make sure privilege is still 0
+ */
+ mov r16=r0
+ DO_SAVE_SWITCH_STACK
+ br.call.sptk.many rp=ia64_handle_privop // stack frame setup in ivt
+.ret22: .body
+ DO_LOAD_SWITCH_STACK
+ br.cond.sptk.many rp // goes to ia64_leave_kernel
+END(ia64_prepare_handle_privop)
+
+GLOBAL_ENTRY(ia64_prepare_handle_break)
+ .prologue
+ /*
+ * r16 = fake ar.pfs, we simply need to make sure privilege is still 0
+ */
+ mov r16=r0
+ DO_SAVE_SWITCH_STACK
+ br.call.sptk.many rp=ia64_handle_break // stack frame setup in ivt
+.ret23: .body
+ DO_LOAD_SWITCH_STACK
+ br.cond.sptk.many rp // goes to ia64_leave_kernel
+END(ia64_prepare_handle_break)
+
+GLOBAL_ENTRY(ia64_prepare_handle_reflection)
+ .prologue
+ /*
+ * r16 = fake ar.pfs, we simply need to make sure privilege is still 0
+ */
+ mov r16=r0
+ DO_SAVE_SWITCH_STACK
+ br.call.sptk.many rp=ia64_handle_reflection // stack frame setup in ivt
+.ret24: .body
+ DO_LOAD_SWITCH_STACK
+ br.cond.sptk.many rp // goes to ia64_leave_kernel
+END(ia64_prepare_handle_reflection)
+
+// NOTE: instruction spacing must be explicit for recovery on miss
+GLOBAL_ENTRY(__get_domain_bundle)
+ ld8 r8=[r32],8
+ nop 0
+ nop 0
+ ;;
+ ld8 r9=[r32]
+ nop 0
+ nop 0
+ ;;
+ br.ret.sptk.many rp
+ nop 0
+ nop 0
+ ;;
+END(__get_domain_bundle)
+
+GLOBAL_ENTRY(dorfirfi)
+#define SI_CR_IIP_OFFSET 0x150
+#define SI_CR_IPSR_OFFSET 0x148
+#define SI_CR_IFS_OFFSET 0x158
+ movl r16 = SHAREDINFO_ADDR+SI_CR_IIP_OFFSET
+ movl r17 = SHAREDINFO_ADDR+SI_CR_IPSR_OFFSET
+ movl r18 = SHAREDINFO_ADDR+SI_CR_IFS_OFFSET
+ ;;
+ ld8 r16 = [r16]
+ ld8 r17 = [r17]
+ ld8 r18 = [r18]
+ ;;
+ mov cr.iip=r16
+ mov cr.ipsr=r17
+ mov cr.ifs=r18
+ ;;
+ // fall through
+END(dorfirfi)
+
+GLOBAL_ENTRY(dorfi)
+ rfi
+ ;;
+END(dorfirfi)
+
+//
+// Long's Peak UART Offsets
+//
+#define COM_TOP 0xff5e0000
+#define COM_BOT 0xff5e2000
+
+// UART offsets
+#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */
+#define UART_INT_ENB 1 /* interrupt enable (DLAB=0) */
+#define UART_INT_ID 2 /* Interrupt ID register */
+#define UART_LINE_CTL 3 /* Line control register */
+#define UART_MODEM_CTL 4 /* Modem Control Register */
+#define UART_LSR 5 /* In: Line Status Register */
+#define UART_MSR 6 /* Modem status register */
+#define UART_DLATCH_LOW UART_TX
+#define UART_DLATCH_HIGH UART_INT_ENB
+#define COM1 0x3f8
+#define COM2 0x2F8
+#define COM3 0x3E8
+
+/* interrupt enable bits (offset 1) */
+#define DATA_AVAIL_INT 1
+#define XMIT_HOLD_EMPTY_INT 2
+#define LINE_STAT_INT 4
+#define MODEM_STAT_INT 8
+
+/* line status bits (offset 5) */
+#define REC_DATA_READY 1
+#define OVERRUN 2
+#define PARITY_ERROR 4
+#define FRAMING_ERROR 8
+#define BREAK_INTERRUPT 0x10
+#define XMIT_HOLD_EMPTY 0x20
+#define XMIT_SHIFT_EMPTY 0x40
+
+// Write a single character
+// input: r32 = character to be written
+// output: none
+GLOBAL_ENTRY(longs_peak_putc)
+ rsm psr.dt
+ movl r16 = 0x8000000000000000 + COM_TOP + UART_LSR
+ ;;
+ srlz.i
+ ;;
+
+.Chk_THRE_p:
+ ld1.acq r18=[r16]
+ ;;
+
+ and r18 = XMIT_HOLD_EMPTY, r18
+ ;;
+ cmp4.eq p6,p0=0,r18
+ ;;
+
+(p6) br .Chk_THRE_p
+ ;;
+ movl r16 = 0x8000000000000000 + COM_TOP + UART_TX
+ ;;
+ st1.rel [r16]=r32
+ ;;
+ ssm psr.dt
+ ;;
+ srlz.i
+ ;;
+ br.ret.sptk.many b0
+END(longs_peak_putc)
+
+/* derived from linux/arch/ia64/hp/sim/boot/boot_head.S */
+GLOBAL_ENTRY(pal_emulator_static)
+ mov r8=-1
+ mov r9=256
+ ;;
+ cmp.gtu p7,p8=r9,r32 /* r32 <= 255? */
+(p7) br.cond.sptk.few static
+ ;;
+ mov r9=512
+ ;;
+ cmp.gtu p7,p8=r9,r32
+(p7) br.cond.sptk.few stacked
+ ;;
+static: cmp.eq p7,p8=6,r32 /* PAL_PTCE_INFO */
+(p8) br.cond.sptk.few 1f
+ ;;
+ mov r8=0 /* status = 0 */
+ movl r9=0x100000000 /* tc.base */
+ movl r10=0x0000000200000003 /* count[0], count[1] */
+ movl r11=0x1000000000002000 /* stride[0], stride[1] */
+ br.ret.sptk.few rp
+1: cmp.eq p7,p8=14,r32 /* PAL_FREQ_RATIOS */
+(p8) br.cond.sptk.few 1f
+ mov r8=0 /* status = 0 */
+ movl r9 =0x900000002 /* proc_ratio (1/100) */
+ movl r10=0x100000100 /* bus_ratio<<32 (1/256) */
+ movl r11=0x900000002 /* itc_ratio<<32 (1/100) */
+ ;;
+1: cmp.eq p7,p8=19,r32 /* PAL_RSE_INFO */
+(p8) br.cond.sptk.few 1f
+ mov r8=0 /* status = 0 */
+ mov r9=96 /* num phys stacked */
+ mov r10=0 /* hints */
+ mov r11=0
+ br.ret.sptk.few rp
+1: cmp.eq p7,p8=1,r32 /* PAL_CACHE_FLUSH */
+(p8) br.cond.sptk.few 1f
+#if 0
+ mov r9=ar.lc
+ movl r8=524288 /* flush 512k million cache lines (16MB) */
+ ;;
+ mov ar.lc=r8
+ movl r8=0xe000000000000000
+ ;;
+.loop: fc r8
+ add r8=32,r8
+ br.cloop.sptk.few .loop
+ sync.i
+ ;;
+ srlz.i
+ ;;
+ mov ar.lc=r9
+ mov r8=r0
+ ;;
+1: cmp.eq p7,p8=15,r32 /* PAL_PERF_MON_INFO */
+(p8) br.cond.sptk.few 1f
+ mov r8=0 /* status = 0 */
+ movl r9 =0x08122f04 /* generic=4 width=47 retired=8 cycles=18 */
+ mov r10=0 /* reserved */
+ mov r11=0 /* reserved */
+ mov r16=0xffff /* implemented PMC */
+ mov r17=0x3ffff /* implemented PMD */
+ add r18=8,r29 /* second index */
+ ;;
+ st8 [r29]=r16,16 /* store implemented PMC */
+ st8 [r18]=r0,16 /* clear remaining bits */
+ ;;
+ st8 [r29]=r0,16 /* clear remaining bits */
+ st8 [r18]=r0,16 /* clear remaining bits */
+ ;;
+ st8 [r29]=r17,16 /* store implemented PMD */
+ st8 [r18]=r0,16 /* clear remaining bits */
+ mov r16=0xf0 /* cycles count capable PMC */
+ ;;
+ st8 [r29]=r0,16 /* clear remaining bits */
+ st8 [r18]=r0,16 /* clear remaining bits */
+ mov r17=0xf0 /* retired bundles capable PMC */
+ ;;
+ st8 [r29]=r16,16 /* store cycles capable */
+ st8 [r18]=r0,16 /* clear remaining bits */
+ ;;
+ st8 [r29]=r0,16 /* clear remaining bits */
+ st8 [r18]=r0,16 /* clear remaining bits */
+ ;;
+ st8 [r29]=r17,16 /* store retired bundle capable */
+ st8 [r18]=r0,16 /* clear remaining bits */
+ ;;
+ st8 [r29]=r0,16 /* clear remaining bits */
+ st8 [r18]=r0,16 /* clear remaining bits */
+ ;;
+1: br.cond.sptk.few rp
+#else
+1:
+#endif
+stacked:
+ br.ret.sptk.few rp
+END(pal_emulator_static)